From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- .../Library/FileExplorerLib/FileExplorer.c | 1653 ++++++++++++++++++++ .../Library/FileExplorerLib/FileExplorer.h | 236 +++ .../Library/FileExplorerLib/FileExplorerLib.inf | 57 + .../Library/FileExplorerLib/FileExplorerLib.uni | 20 + .../Library/FileExplorerLib/FileExplorerString.uni | 55 + .../Library/FileExplorerLib/FileExplorerVfr.vfr | 79 + .../Library/FileExplorerLib/FormGuid.h | 32 + 7 files changed, 2132 insertions(+) create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr create mode 100644 roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h (limited to 'roms/edk2/MdeModulePkg/Library/FileExplorerLib') diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c new file mode 100644 index 000000000..58e491025 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c @@ -0,0 +1,1653 @@ +/** @file +File explorer related functions. + +Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#include "FileExplorer.h" + +EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID; + +/// +/// File system selection menu +/// +MENU_OPTION mFsOptionMenu = { + MENU_OPTION_SIGNATURE, + {NULL}, + 0, + FALSE +}; + +FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = { + FILE_EXPLORER_CALLBACK_DATA_SIGNATURE, + NULL, + NULL, + { + LibExtractConfig, + LibRouteConfig, + LibCallback + }, + NULL, + &mFsOptionMenu, + 0 +}; + +HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath; + +HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + // + // Will be replace with gEfiCallerIdGuid in code. + // + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +VOID *mLibStartOpCodeHandle = NULL; +VOID *mLibEndOpCodeHandle = NULL; +EFI_IFR_GUID_LABEL *mLibStartLabel = NULL; +EFI_IFR_GUID_LABEL *mLibEndLabel = NULL; +UINT16 mQuestionIdUpdate; +CHAR16 mNewFileName[MAX_FILE_NAME_LEN]; +CHAR16 mNewFolderName[MAX_FOLDER_NAME_LEN]; +UINTN mNewFileQuestionId = NEW_FILE_QUESTION_ID_BASE; +UINTN mNewFolderQuestionId = NEW_FOLDER_QUESTION_ID_BASE; + +/** + Create a new file or folder in current directory. + + @param FileName Point to the fileNmae or folder. + @param CreateFile CreateFile== TRUE means create a new file. + CreateFile== FALSE means create a new Folder. + +**/ +EFI_STATUS +LibCreateNewFile ( + IN CHAR16 *FileName, + IN BOOLEAN CreateFile + ); + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in 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 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 format. + @param Progress A pointer to a string filled in with the offset of the most + recent '&' before the first failing name/value pair (or the + beginning of the string if the failure is in the first + name/value pair) or the terminating NULL if all was successful. + + @retval EFI_INVALID_PARAMETER Configuration is NULL. + @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver. + +**/ +EFI_STATUS +EFIAPI +LibRouteConfig ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN CONST EFI_STRING Configuration, + OUT EFI_STRING *Progress + ) +{ + if (Configuration == NULL || Progress == NULL) { + return EFI_INVALID_PARAMETER; + } + + *Progress = Configuration; + return EFI_NOT_FOUND; +} + +/** + This function processes the results of changes in configuration. + When user select a interactive opcode, this callback will be triggered. + Based on the Question(QuestionId) that triggers the callback, the corresponding + actions is performed. It handles: + + 1) Process the axtra action or exit file explorer when user select one file . + 2) update of file content if a dir is selected. + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Action Specifies the type of action taken by the browser. + @param QuestionId A unique value which is sent to the original exporting driver + so that it can identify the type of data to expect. + @param Type The type of value for the question. + @param Value A pointer to the data being sent to the original exporting driver. + @param ActionRequest On return, points to the action requested by the callback function. + + @retval EFI_SUCCESS The callback successfully handled the action. + @retval other error Error occur when parse one directory. +**/ +EFI_STATUS +EFIAPI +LibCallback ( + IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, + IN EFI_BROWSER_ACTION Action, + IN EFI_QUESTION_ID QuestionId, + IN UINT8 Type, + IN EFI_IFR_TYPE_VALUE *Value, + OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest + ) +{ + EFI_STATUS Status; + BOOLEAN NeedExit; + CHAR16 *NewFileName; + CHAR16 *NewFolderName; + + NeedExit = TRUE; + NewFileName = NULL; + NewFolderName = NULL; + + if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) { + // + // Do nothing for other UEFI Action. Only do call back when data is changed. + // + return EFI_UNSUPPORTED; + } + + if (Action == EFI_BROWSER_ACTION_CHANGED) { + if ((Value == NULL) || (ActionRequest == NULL)) { + return EFI_INVALID_PARAMETER; + } + + if (QuestionId == KEY_VALUE_CREATE_FILE_AND_EXIT) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + if (!IsZeroBuffer (mNewFileName, sizeof (mNewFileName))) { + Status = LibCreateNewFile (mNewFileName,TRUE); + ZeroMem (mNewFileName,sizeof (mNewFileName)); + } + } + + if (QuestionId == KEY_VALUE_NO_CREATE_FILE_AND_EXIT) { + ZeroMem (mNewFileName,sizeof (mNewFileName)); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + + if (QuestionId == KEY_VALUE_CREATE_FOLDER_AND_EXIT) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + if (!IsZeroBuffer (mNewFolderName, sizeof (mNewFolderName))) { + Status = LibCreateNewFile (mNewFolderName, FALSE); + ZeroMem (mNewFolderName,sizeof (mNewFolderName)); + } + } + + if (QuestionId == KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT) { + ZeroMem (mNewFolderName,sizeof (mNewFolderName)); + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + + if (QuestionId == NEW_FILE_NAME_ID) { + NewFileName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL); + if (NewFileName != NULL) { + StrCpyS (mNewFileName, MAX_FILE_NAME_LEN, NewFileName); + FreePool (NewFileName); + NewFileName = NULL; + } else { + return EFI_INVALID_PARAMETER; + } + } + + if (QuestionId == NEW_FOLDER_NAME_ID) { + NewFolderName = HiiGetString (gFileExplorerPrivate.FeHiiHandle, Value->string, NULL); + if (NewFolderName != NULL) { + StrCpyS (mNewFolderName, MAX_FOLDER_NAME_LEN, NewFolderName); + FreePool (NewFolderName); + NewFolderName = NULL; + } else { + return EFI_INVALID_PARAMETER; + } + } + + if (QuestionId >= FILE_OPTION_OFFSET) { + LibGetDevicePath(QuestionId); + + // + // Process the extra action. + // + if (gFileExplorerPrivate.ChooseHandler != NULL) { + NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath); + } + + if (NeedExit) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + } + } else if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (Value == NULL) { + return EFI_INVALID_PARAMETER; + } + if (QuestionId >= FILE_OPTION_OFFSET) { + LibGetDevicePath(QuestionId); + Status = LibUpdateFileExplorer (QuestionId); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +/** + Create a menu entry by given menu type. + + @retval NULL If failed to create the menu. + @return the new menu entry. + +**/ +MENU_ENTRY * +LibCreateMenuEntry ( + VOID + ) +{ + MENU_ENTRY *MenuEntry; + + // + // Create new menu entry + // + MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY)); + if (MenuEntry == NULL) { + return NULL; + } + + MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT)); + if (MenuEntry->VariableContext == NULL) { + FreePool (MenuEntry); + return NULL; + } + + MenuEntry->Signature = MENU_ENTRY_SIGNATURE; + return MenuEntry; +} + + +/** + Get the Menu Entry from the list in Menu Entry List. + + If MenuNumber is great or equal to the number of Menu + Entry in the list, then ASSERT. + + @param MenuOption The Menu Entry List to read the menu entry. + @param MenuNumber The index of Menu Entry. + + @return The Menu Entry. + +**/ +MENU_ENTRY * +LibGetMenuEntry ( + MENU_OPTION *MenuOption, + UINTN MenuNumber + ) +{ + MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + ASSERT (MenuNumber < MenuOption->MenuNumber); + + List = MenuOption->Head.ForwardLink; + for (Index = 0; Index < MenuNumber; Index++) { + List = List->ForwardLink; + } + + NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE); + + return NewMenuEntry; +} + +/** + Free up all resource allocated for a BM_MENU_ENTRY. + + @param MenuEntry A pointer to BM_MENU_ENTRY. + +**/ +VOID +LibDestroyMenuEntry ( + MENU_ENTRY *MenuEntry + ) +{ + FILE_CONTEXT *FileContext; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + + if (!FileContext->IsRoot) { + if (FileContext->DevicePath != NULL) { + FreePool (FileContext->DevicePath); + } + } else { + if (FileContext->FileHandle != NULL) { + FileContext->FileHandle->Close (FileContext->FileHandle); + } + } + + if (FileContext->FileName != NULL) { + FreePool (FileContext->FileName); + } + + FreePool (FileContext); + + if (MenuEntry->DisplayString != NULL) { + FreePool (MenuEntry->DisplayString); + } + if (MenuEntry->HelpString != NULL) { + FreePool (MenuEntry->HelpString); + } + + FreePool (MenuEntry); +} + + +/** + Free resources allocated in Allocate Rountine. + + @param FreeMenu Menu to be freed +**/ +VOID +LibFreeMenu ( + MENU_OPTION *FreeMenu + ) +{ + MENU_ENTRY *MenuEntry; + while (!IsListEmpty (&FreeMenu->Head)) { + MenuEntry = CR ( + FreeMenu->Head.ForwardLink, + MENU_ENTRY, + Link, + MENU_ENTRY_SIGNATURE + ); + RemoveEntryList (&MenuEntry->Link); + LibDestroyMenuEntry (MenuEntry); + } + FreeMenu->MenuNumber = 0; +} + +/** + + Function opens and returns a file handle to the root directory of a volume. + + @param DeviceHandle A handle for a device + + @return A valid file handle or NULL is returned + +**/ +EFI_FILE_HANDLE +LibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE File; + + File = NULL; + + // + // File the file system interface to the device + // + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID *) &Volume + ); + + // + // Open the root directory of the volume + // + if (!EFI_ERROR (Status)) { + Status = Volume->OpenVolume ( + Volume, + &File + ); + } + // + // Done + // + return EFI_ERROR (Status) ? NULL : File; +} + +/** + This function converts an input device structure to a Unicode string. + + @param DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +LibDevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + if (DevPath == NULL) { + return NULL; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + ASSERT_EFI_ERROR (Status); + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + + return ToText; +} + +/** + Duplicate a string. + + @param Src The source. + + @return A new string which is duplicated copy of the source. + @retval NULL If there is not enough memory. + +**/ +CHAR16 * +LibStrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); + Dest = AllocateZeroPool (Size); + ASSERT (Dest != NULL); + if (Dest != NULL) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +/** + + Function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + + @param FHand File Handle. + @param InfoType Info type need to get. + + @retval A pointer to a buffer with file information or NULL is returned + +**/ +VOID * +LibFileInfo ( + IN EFI_FILE_HANDLE FHand, + IN EFI_GUID *InfoType + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + Buffer = NULL; + BufferSize = 0; + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocatePool (BufferSize); + ASSERT (Buffer != NULL); + } + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + + return Buffer; +} + +/** + + Get file type base on the file name. + Just cut the file name, from the ".". eg ".efi" + + @param FileName File need to be checked. + + @retval the file type string. + +**/ +CHAR16* +LibGetTypeFromName ( + IN CHAR16 *FileName + ) +{ + UINTN Index; + + Index = StrLen (FileName) - 1; + while ((FileName[Index] != L'.') && (Index != 0)) { + Index--; + } + + return Index == 0 ? NULL : &FileName[Index]; +} + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +LibToLowerString ( + IN CHAR16 *String + ) +{ + CHAR16 *TmpStr; + + for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) { + if (*TmpStr >= L'A' && *TmpStr <= L'Z') { + *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a'); + } + } +} + +/** + + Check whether current FileName point to a valid + Efi Image File. + + @param FileName File need to be checked. + + @retval TRUE Is Efi Image + @retval FALSE Not a valid Efi Image + +**/ +BOOLEAN +LibIsSupportedFileType ( + IN UINT16 *FileName + ) +{ + CHAR16 *InputFileType; + CHAR16 *TmpStr; + BOOLEAN IsSupported; + + if (gFileExplorerPrivate.FileType == NULL) { + return TRUE; + } + + InputFileType = LibGetTypeFromName (FileName); + // + // If the file not has *.* style, always return TRUE. + // + if (InputFileType == NULL) { + return TRUE; + } + + TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType); + ASSERT(TmpStr != NULL); + LibToLowerString(TmpStr); + + IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE); + + FreePool (TmpStr); + return IsSupported; +} + +/** + + Append file name to existing file name. + + @param Str1 The existing file name + @param Str2 The file name to be appended + + @return Allocate a new string to hold the appended result. + Caller is responsible to free the returned string. + +**/ +CHAR16 * +LibAppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +{ + UINTN Size1; + UINTN Size2; + UINTN MaxLen; + CHAR16 *Str; + CHAR16 *TmpStr; + CHAR16 *Ptr; + CHAR16 *LastSlash; + + Size1 = StrSize (Str1); + Size2 = StrSize (Str2); + + // + // Check overflow + // + if (((MAX_UINTN - Size1) < Size2) || ((MAX_UINTN - Size1 - Size2) < sizeof(CHAR16))) { + return NULL; + } + + MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16); + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (Str != NULL); + + TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (TmpStr != NULL); + + StrCpyS (Str, MaxLen, Str1); + if (!((*Str == '\\') && (*(Str + 1) == 0))) { + StrCatS (Str, MaxLen, L"\\"); + } + + StrCatS (Str, MaxLen, Str2); + + Ptr = Str; + LastSlash = Str; + while (*Ptr != 0) { + if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { + // + // Convert "\Name\..\" to "\" + // DO NOT convert the .. if it is at the end of the string. This will + // break the .. behavior in changing directories. + // + + // + // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpyS (TmpStr, MaxLen, Ptr + 3); + StrCpyS (LastSlash, MaxLen - ((UINTN) LastSlash - (UINTN) Str) / sizeof (CHAR16), TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { + // + // Convert a "\.\" to a "\" + // + + // + // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpyS (TmpStr, MaxLen, Ptr + 2); + StrCpyS (Ptr, MaxLen - ((UINTN) Ptr - (UINTN) Str) / sizeof (CHAR16), TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\') { + LastSlash = Ptr; + } + + Ptr++; + } + + FreePool (TmpStr); + + return Str; +} + +/** + This function build the FsOptionMenu list which records all + available file system in the system. They includes all instances + of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM. + + + @retval EFI_SUCCESS Success find the file system + @retval EFI_OUT_OF_RESOURCES Can not create menu entry + +**/ +EFI_STATUS +LibFindFileSystem ( + VOID + ) +{ + UINTN NoSimpleFsHandles; + EFI_HANDLE *SimpleFsHandle; + UINT16 *VolumeLabel; + UINTN Index; + EFI_STATUS Status; + MENU_ENTRY *MenuEntry; + FILE_CONTEXT *FileContext; + UINTN OptionNumber; + EFI_FILE_SYSTEM_VOLUME_LABEL *Info; + + NoSimpleFsHandles = 0; + OptionNumber = 0; + + // + // Locate Handles that support Simple File System protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoSimpleFsHandles, + &SimpleFsHandle + ); + if (!EFI_ERROR (Status)) { + // + // Find all the instances of the File System prototocol + // + for (Index = 0; Index < NoSimpleFsHandles; Index++) { + // + // Allocate pool for this load option + // + MenuEntry = LibCreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (SimpleFsHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->DeviceHandle = SimpleFsHandle[Index]; + FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle); + if (FileContext->FileHandle == NULL) { + LibDestroyMenuEntry (MenuEntry); + continue; + } + + MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle)); + FileContext->FileName = LibStrDuplicate (L"\\"); + FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName); + FileContext->IsDir = TRUE; + FileContext->IsRoot = TRUE; + + // + // Get current file system's Volume Label + // + Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid); + if (Info == NULL) { + VolumeLabel = L"NO FILE SYSTEM INFO"; + } else { + 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 + ); + + if (Info != NULL) + FreePool (Info); + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); + } + } + + if (NoSimpleFsHandles != 0) { + FreePool (SimpleFsHandle); + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input menu info. + + @param MenuEntry Input Menu info. + @param RetFileHandle Return the file handle for the input device path. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromMenu ( + IN MENU_ENTRY *MenuEntry, + OUT EFI_FILE_HANDLE *RetFileHandle + ) +{ + EFI_FILE_HANDLE Dir; + EFI_FILE_HANDLE NewDir; + FILE_CONTEXT *FileContext; + EFI_STATUS Status; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + Dir = FileContext->FileHandle; + + // + // Open current directory to get files from it + // + Status = Dir->Open ( + Dir, + &NewDir, + FileContext->FileName, + EFI_FILE_READ_ONLY, + 0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!FileContext->IsRoot) { + Dir->Close (Dir); + } + + *RetFileHandle = NewDir; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input device path info. + + @param RootDirectory Device path info. + @param RetFileHandle Return the file handle for the input device path. + @param ParentFileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + OUT EFI_FILE_HANDLE *RetFileHandle, + OUT UINT16 **ParentFileName, + OUT EFI_HANDLE *DeviceHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE LastHandle; + CHAR16 *TempPath; + + *ParentFileName = NULL; + + // + // Attempt to access the file via a file system interface + // + DevicePathNode = RootDirectory; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the Volume to get the File System handle + // + Status = Volume->OpenVolume (Volume, &FileHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + *DeviceHandle = Handle; + + if (IsDevicePathEnd(DevicePathNode)) { + *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\"); + *RetFileHandle = FileHandle; + return EFI_SUCCESS; + } + + // + // Duplicate the device path to avoid the access to unaligned device path node. + // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH + // nodes, It assures the fields in device path nodes are 2 byte aligned. + // + TempDevicePathNode = DuplicateDevicePath (DevicePathNode); + if (TempDevicePathNode == NULL) { + + // + // Setting Status to an EFI_ERROR value will cause the rest of + // the file system support below to be skipped. + // + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + // + // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the + // directory information and filename can be seperate. The goal is to inch + // our way down each device path node and close the previous node + // + DevicePathNode = TempDevicePathNode; + while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) { + if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH || + DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + LastHandle = FileHandle; + FileHandle = NULL; + + Status = LastHandle->Open ( + LastHandle, + &FileHandle, + ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName, + EFI_FILE_MODE_READ, + 0 + ); + if (*ParentFileName == NULL) { + *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + } else { + TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + if (TempPath == NULL) { + LastHandle->Close (LastHandle); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + FreePool (*ParentFileName); + *ParentFileName = TempPath; + } + + // + // Close the previous node + // + LastHandle->Close (LastHandle); + + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + *RetFileHandle = FileHandle; + + Status = EFI_SUCCESS; + +Done: + if (TempDevicePathNode != NULL) { + FreePool (TempDevicePathNode); + } + + if ((FileHandle != NULL) && (EFI_ERROR (Status))) { + FileHandle->Close (FileHandle); + } + + return Status; +} + +/** + Create a new file or folder in current directory. + + @param FileName Point to the fileNmae or folder name. + @param CreateFile CreateFile== TRUE means create a new file. + CreateFile== FALSE means create a new Folder. + +**/ +EFI_STATUS +LibCreateNewFile ( + IN CHAR16 *FileName, + IN BOOLEAN CreateFile + ) +{ + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE NewHandle; + EFI_HANDLE DeviceHandle; + EFI_STATUS Status; + CHAR16 *ParentName; + CHAR16 *FullFileName; + + NewHandle = NULL; + FullFileName = NULL; + + LibGetFileHandleFromDevicePath(gFileExplorerPrivate.RetDevicePath, &FileHandle, &ParentName, &DeviceHandle); + FullFileName = LibAppendFileName (ParentName, FileName); + if (FullFileName == NULL) { + return EFI_OUT_OF_RESOURCES; + } + if (CreateFile) { + Status = FileHandle->Open( + FileHandle, + &NewHandle, + FullFileName, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE, + 0 + ); + if (EFI_ERROR (Status)) { + FileHandle->Close (FileHandle); + return Status; + } + } else { + Status = FileHandle->Open( + FileHandle, + &NewHandle, + FullFileName, + EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE| EFI_FILE_MODE_CREATE, + EFI_FILE_DIRECTORY + ); + if (EFI_ERROR (Status)) { + FileHandle->Close (FileHandle); + return Status; + } + } + + FileHandle->Close (FileHandle); + + // + // Return the DevicePath of the new created file or folder. + // + gFileExplorerPrivate.RetDevicePath = FileDevicePath (DeviceHandle, FullFileName); + + return EFI_SUCCESS; + +} + +/** + Find files under current directory. + + All files and sub-directories in current directory + will be stored in DirectoryMenu for future use. + + @param FileHandle Parent file handle. + @param FileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCCESS Get files from current dir successfully. + @return Other value if can't get files from current dir. + +**/ +EFI_STATUS +LibFindFiles ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT16 *FileName, + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_FILE_INFO *DirInfo; + UINTN BufferSize; + UINTN DirBufferSize; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + UINTN Pass; + EFI_STATUS Status; + UINTN OptionNumber; + + OptionNumber = 0; + + DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; + DirInfo = AllocateZeroPool (DirBufferSize); + if (DirInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all files in current directory + // Pass 1 to get Directories + // Pass 2 to get files that are EFI images + // + Status = EFI_SUCCESS; + for (Pass = 1; Pass <= 2; Pass++) { + FileHandle->SetPosition (FileHandle, 0); + for (;;) { + BufferSize = DirBufferSize; + Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo); + if (EFI_ERROR (Status) || BufferSize == 0) { + Status = EFI_SUCCESS; + break; + } + + if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || + ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) + ) { + // + // Pass 1 is for Directories + // Pass 2 is for file names + // + continue; + } + + if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) { + // + // Slip file unless it is a directory entry or a .EFI file + // + continue; + } + + NewMenuEntry = LibCreateMenuEntry (); + if (NULL == NewMenuEntry) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + NewFileContext->DeviceHandle = DeviceHandle; + NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName); + if (NewFileContext->FileName == NULL) { + LibDestroyMenuEntry (NewMenuEntry); + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + NewFileContext->FileHandle = FileHandle; + NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName); + NewMenuEntry->HelpString = NULL; + NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); + + if (NewFileContext->IsDir) { + BufferSize = StrLen (DirInfo->FileName) * 2 + 6; + NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); + UnicodeSPrint ( + NewMenuEntry->DisplayString, + BufferSize, + L"<%s>", + DirInfo->FileName + ); + } else { + NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName); + } + + NewMenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + NewMenuEntry->DisplayString, + NULL + ); + + NewFileContext->IsRoot = FALSE; + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link); + } + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + +Done: + + FreePool (DirInfo); + + return Status; +} + +/** + Refresh the global UpdateData structure. + +**/ +VOID +LibRefreshUpdateData ( + VOID + ) +{ + // + // Free current updated date + // + if (mLibStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibStartOpCodeHandle); + } + if (mLibEndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibEndOpCodeHandle); + } + + // + // Create new OpCode Handle + // + mLibStartOpCodeHandle = HiiAllocateOpCodeHandle (); + mLibEndOpCodeHandle = HiiAllocateOpCodeHandle (); + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibStartLabel->Number = FORM_FILE_EXPLORER_ID; + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibEndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibEndLabel->Number = LABEL_END; +} + +/** + + Update the File Explore page. + +**/ +VOID +LibUpdateFileExplorePage ( + VOID + ) +{ + UINTN Index; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + MENU_OPTION *MenuOption; + BOOLEAN CreateNewFile; + + NewMenuEntry = NULL; + NewFileContext = NULL; + CreateNewFile = FALSE; + + LibRefreshUpdateData (); + MenuOption = gFileExplorerPrivate.FsOptionMenu; + + mQuestionIdUpdate += QUESTION_ID_UPDATE_STEP; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = LibGetMenuEntry (MenuOption, Index); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (!NewFileContext->IsRoot && !CreateNewFile) { + HiiCreateGotoOpCode ( + mLibStartOpCodeHandle, + FORM_ADD_NEW_FILE_ID, + STRING_TOKEN (STR_NEW_FILE), + STRING_TOKEN (STR_NEW_FILE_HELP), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (mNewFileQuestionId++) + ); + HiiCreateGotoOpCode ( + mLibStartOpCodeHandle, + FORM_ADD_NEW_FOLDER_ID, + STRING_TOKEN (STR_NEW_FOLDER), + STRING_TOKEN (STR_NEW_FOLDER_HELP), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (mNewFolderQuestionId++) + ); + HiiCreateTextOpCode( + mLibStartOpCodeHandle, + STRING_TOKEN (STR_NULL_STRING), + STRING_TOKEN (STR_NULL_STRING), + 0 + ); + CreateNewFile = TRUE; + } + + if (!NewFileContext->IsDir) { + // + // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. + // + HiiCreateActionOpCode ( + mLibStartOpCodeHandle, + (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate), + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + 0 + ); + } else { + // + // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState. + // + HiiCreateGotoOpCode ( + mLibStartOpCodeHandle, + FORM_FILE_EXPLORER_ID, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (FILE_OPTION_OFFSET + Index + mQuestionIdUpdate) + ); + } + } + + HiiUpdateForm ( + gFileExplorerPrivate.FeHiiHandle, + &FileExplorerGuid, + FORM_FILE_EXPLORER_ID, + mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID + mLibEndOpCodeHandle // LABEL_END + ); +} + +/** + Update the file explower page with the refershed file system. + + @param KeyValue Key value to identify the type of data to expect. + + @retval EFI_SUCCESS Update the file explorer form success. + @retval other errors Error occur when parse one directory. + +**/ +EFI_STATUS +LibUpdateFileExplorer ( + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + + Status = EFI_SUCCESS; + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue) - mQuestionIdUpdate; + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (NewFileContext->IsDir) { + RemoveEntryList (&NewMenuEntry->Link); + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + 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) - mQuestionIdUpdate; + + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath); +} + +/** + Choose a file in the specified directory. + + If user input NULL for the RootDirectory, will choose file in the system. + + If user input *File != NULL, function will return the allocate device path + info for the choosed file, caller has to free the memory after use it. + + @param RootDirectory Pointer to the root directory. + @param FileType The file type need to choose. + @param ChooseHandler Function pointer to the extra task need to do + after choose one file. + @param File Return the device path for the last time chosed file. + + @retval EFI_SUCESS Choose file success. + @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL + One of them must not NULL. + @retval Other errors Choose file failed. +**/ +EFI_STATUS +EFIAPI +ChooseFile ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + IN CHAR16 *FileType, OPTIONAL + IN CHOOSE_HANDLER ChooseHandler, OPTIONAL + OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL + ) +{ + EFI_FILE_HANDLE FileHandle; + EFI_STATUS Status; + UINT16 *FileName; + EFI_HANDLE DeviceHandle; + + if ((ChooseHandler == NULL) && (File == NULL)) { + return EFI_INVALID_PARAMETER; + } + + mQuestionIdUpdate = 0; + FileName = NULL; + + gFileExplorerPrivate.RetDevicePath = NULL; + gFileExplorerPrivate.ChooseHandler = ChooseHandler; + if (FileType != NULL) { + gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType); + ASSERT(gFileExplorerPrivate.FileType != NULL); + LibToLowerString(gFileExplorerPrivate.FileType); + } else { + gFileExplorerPrivate.FileType = NULL; + } + + if (RootDirectory == NULL) { + Status = LibFindFileSystem(); + } else { + Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = LibFindFiles (FileHandle, FileName, DeviceHandle); + } + if (EFI_ERROR (Status)) { + goto Done; + } + + LibUpdateFileExplorePage(); + + gFileExplorerPrivate.FormBrowser2->SendForm ( + gFileExplorerPrivate.FormBrowser2, + &gFileExplorerPrivate.FeHiiHandle, + 1, + &FileExplorerGuid, + 0, + NULL, + NULL + ); + +Done: + if ((Status == EFI_SUCCESS) && (File != NULL)) { + *File = gFileExplorerPrivate.RetDevicePath; + } else if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + + if (gFileExplorerPrivate.FileType != NULL) { + FreePool (gFileExplorerPrivate.FileType); + } + + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + + if (FileName != NULL) { + FreePool (FileName); + } + + return Status; +} + +/** + + Install Boot Manager Menu driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCEESS Install File explorer library success. + +**/ +EFI_STATUS +EFIAPI +FileExplorerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); + ASSERT (gHiiVendorDevicePath != NULL); + CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid); + + // + // Install Device Path Protocol and Config Access protocol to driver handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + if (Status == EFI_ALREADY_STARTED) { + return EFI_SUCCESS; + } + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Post our File Explorer VFR binary to the HII database. + // + gFileExplorerPrivate.FeHiiHandle = HiiAddPackages ( + &FileExplorerGuid, + gFileExplorerPrivate.FeDriverHandle, + FileExplorerVfrBin, + FileExplorerLibStrings, + NULL + ); + ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL); + + // + // Locate Formbrowser2 protocol + // + Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2); + ASSERT_EFI_ERROR (Status); + + InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head); + + return EFI_SUCCESS; +} + +/** + Unloads the application and its installed protocol. + + @param[in] ImageHandle Handle that identifies the image to be unloaded. + @param[in] SystemTable The system table. + + @retval EFI_SUCCESS The image has been unloaded. +**/ +EFI_STATUS +EFIAPI +FileExplorerLibDestructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + ASSERT (gHiiVendorDevicePath != NULL); + + if (gFileExplorerPrivate.FeDriverHandle != NULL) { + Status = gBS->UninstallMultipleProtocolInterfaces ( + gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle); + gFileExplorerPrivate.FeDriverHandle = NULL; + } + + FreePool (gHiiVendorDevicePath); + + return EFI_SUCCESS; +} + diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h new file mode 100644 index 000000000..cc84c2a65 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h @@ -0,0 +1,236 @@ +/** @file + File explorer lib. + +Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _FILE_EXPLORER_H_ +#define _FILE_EXPLORER_H_ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + +#pragma pack() + +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; + CHAR16 *FileType; + CHOOSE_HANDLER ChooseHandler; + 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) + +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 +#define QUESTION_ID_UPDATE_STEP 200 +#define MAX_FILE_NAME_LEN 20 +#define MAX_FOLDER_NAME_LEN 20 +#define NEW_FILE_QUESTION_ID_BASE 0x5000; +#define NEW_FOLDER_QUESTION_ID_BASE 0x6000; + +/** + 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 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 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 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/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf new file mode 100644 index 000000000..4e14cbc04 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf @@ -0,0 +1,57 @@ +## @file +# library defines a set of interfaces for how to do file explorer. +# +# Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
+# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = FileExplorerLib + MODULE_UNI_FILE = FileExplorerLib.uni + 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 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 + HiiLib + UefiHiiServicesLib + +[Guids] + gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## GUID (Indicate the information type is volume) + gEfiIfrTianoGuid ## SOMETIMES_CONSUMES ## GUID (Extended IFR Guid Opcode) + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES + gEfiHiiConfigAccessProtocolGuid ## PRODUCES + gEfiFormBrowser2ProtocolGuid ## CONSUMES + gEfiDevicePathToTextProtocolGuid ## PRODUCES + +[Depex.common.DXE_DRIVER] + gEfiFormBrowser2ProtocolGuid AND gEfiHiiDatabaseProtocolGuid diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni new file mode 100644 index 000000000..5e7a99cb9 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.uni @@ -0,0 +1,20 @@ +// /** @file +// library defines a set of interfaces for how to do file explorer. +// +// library defines a set of interfaces for how to do file explorer. +// +// Copyright (c) 2015, Intel Corporation. All rights reserved.
+// +// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// **/ + +#string STR_MODULE_ABSTRACT +#language en-US +"library defines a set of interfaces for how to do file explorer." + +#string STR_MODULE_DESCRIPTION +#language en-US +"library defines a set of interfaces for how to do file explorer." + + diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni new file mode 100644 index 000000000..52e5eec5f --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerString.uni @@ -0,0 +1,55 @@ +///** @file +// +// Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +// Module Name: +// +// FileExplorerString.uni +// +// Abstract: +// +// String definitions for file exporer library. +// +// Revision History: +// +// --*/ +/=# + +#langdef en-US "English" +#langdef fr-FR "Français" + +#string STR_NULL_STRING #language en-US " " + #language fr-FR " " +#string STR_FILE_EXPLORER_TITLE #language en-US "File Explorer" + #language fr-FR "File Explorer" +#string STR_NEW_FILE #language en-US "***NEW FILE***" + #language fr-FR "***NEW FILE***" +#string STR_NEW_FILE_HELP #language en-US "This menu used to create a new file in current directory, jump to next page to name the new file" + #language fr-FR "This menu used to create a new file in current directory, jump to next page to name the new file" +#string STR_ADD_NEW_FILE_TITLE #language en-US "Create a new file" + #language fr-FR "Create a new file" +#string STR_ADD_NEW_FOLDER_TITLE #language en-US "Create a new folder" + #language fr-FR "Create a new folder" +#string STR_NEW_FILE_NAME_PROMPT #language en-US "File Name" + #language fr-FR "File Name" +#string STR_NEW_FILE_NAME_HELP #language en-US "Please input a name for the new file" + #language fr-FR "Please input a name for the new file" +#string STR_CREATE_FILE_AND_EXIT #language en-US "Create File and Exit" + #language fr-FR "Create File and Exit" +#string STR_NO_CREATE_FILE_AND_EXIT #language en-US "Discard Create and Exit" + #language fr-FR "Discard Create and Exit" +#string STR_NEW_FOLDER #language en-US "***NEW FOLDER***" + #language fr-FR "***NEW FOLDER***" +#string STR_NEW_FOLDER_HELP #language en-US "This menu used to create a new folder in current directory, jump to next page to name the new folder" + #language fr-FR "This menu used to create a new folder in current directory, jump to next page to name the new folder" +#string STR_ADD_NEW_FOLDER_TITLE #language en-US "Create a new folder" + #language fr-FR "Create a new folder" +#string STR_NEW_FOLDER_NAME_PROMPT #language en-US "Folder Name" + #language fr-FR "Folder Name" +#string STR_NEW_FOLDER_NAME_HELP #language en-US "Please input a name for the new folder" + #language fr-FR "Please input a name for the new folder" +#string STR_CREATE_FOLDER_AND_EXIT #language en-US "Create Folder and Exit" + #language fr-FR "Create Folder and Exit" +#string STR_NO_CREATE_FOLDER_AND_EXIT #language en-US "Discard Create and Exit" + #language fr-FR "Discard Create and Exit" diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr new file mode 100644 index 000000000..a8f273299 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr @@ -0,0 +1,79 @@ +///** @file +// +// File Explorer Formset +// +// Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+// SPDX-License-Identifier: BSD-2-Clause-Patent +// +//**/ + +#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; + + form formid = FORM_ADD_NEW_FILE_ID, + title = STRING_TOKEN(STR_ADD_NEW_FILE_TITLE); + + string + prompt = STRING_TOKEN(STR_NEW_FILE_NAME_PROMPT), + help = STRING_TOKEN(STR_NEW_FILE_NAME_HELP), + flags = INTERACTIVE, + key = NEW_FILE_NAME_ID, + minsize = 2, + maxsize = 20, + endstring; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + text + help = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT), + text = STRING_TOKEN(STR_CREATE_FILE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_CREATE_FILE_AND_EXIT; + + text + help = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT), + text = STRING_TOKEN(STR_NO_CREATE_FILE_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_NO_CREATE_FILE_AND_EXIT; + endform; + + form formid = FORM_ADD_NEW_FOLDER_ID, + title = STRING_TOKEN(STR_ADD_NEW_FOLDER_TITLE); + + string + prompt = STRING_TOKEN(STR_NEW_FOLDER_NAME_PROMPT), + help = STRING_TOKEN(STR_NEW_FOLDER_NAME_HELP), + flags = INTERACTIVE, + key = NEW_FOLDER_NAME_ID, + minsize = 2, + maxsize = 20, + endstring; + + subtitle text = STRING_TOKEN(STR_NULL_STRING); + + text + help = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT), + text = STRING_TOKEN(STR_CREATE_FOLDER_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_CREATE_FOLDER_AND_EXIT; + + text + help = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT), + text = STRING_TOKEN(STR_NO_CREATE_FOLDER_AND_EXIT), + flags = INTERACTIVE, + key = KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT; + endform; + +endformset; diff --git a/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h new file mode 100644 index 000000000..a084a50b3 --- /dev/null +++ b/roms/edk2/MdeModulePkg/Library/FileExplorerLib/FormGuid.h @@ -0,0 +1,32 @@ +/** @file +Formset guids, form id and VarStore data structure for File explorer library. + +Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.
+SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + + +#ifndef _FILE_EXPLORER_FORM_GUID_H_ +#define _FILE_EXPLORER_FORM_GUID_H_ + + +#define EFI_FILE_EXPLORE_FORMSET_GUID \ + { \ + 0xfe561596, 0xe6bf, 0x41a6, {0x83, 0x76, 0xc7, 0x2b, 0x71, 0x98, 0x74, 0xd0} \ + } + +#define FORM_FILE_EXPLORER_ID 0x1000 +#define FORM_ADD_NEW_FILE_ID 0x2000 +#define NEW_FILE_NAME_ID 0x2001 +#define KEY_VALUE_CREATE_FILE_AND_EXIT 0x2002 +#define KEY_VALUE_NO_CREATE_FILE_AND_EXIT 0x2003 +#define FORM_ADD_NEW_FOLDER_ID 0x3000 +#define NEW_FOLDER_NAME_ID 0x3001 +#define KEY_VALUE_CREATE_FOLDER_AND_EXIT 0x3002 +#define KEY_VALUE_NO_CREATE_FOLDER_AND_EXIT 0x3003 + +#define LABEL_END 0xffff + +#endif + -- cgit 1.2.3-korg