From: Eric Dong Date: Wed, 16 Dec 2015 03:21:44 +0000 (+0000) Subject: MdeModulePkg FileExplorerLib: Change file format which has mixed file format. X-Git-Tag: edk2-stable201903~8250 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=4c8274a0d751fb2583d40eaf383b1e018c27e97f MdeModulePkg FileExplorerLib: Change file format which has mixed file format. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Eric Dong Reviewed-by: Liming Gao git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@19297 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c index 65e4785921..c64a94bebe 100644 --- a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.c @@ -1,1507 +1,1507 @@ -/** @file -File explorer related functions. - -Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
-This program and the accompanying materials are licensed and made available under -the terms and conditions of the BSD License that accompanies this distribution. -The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php. - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - - -#include "FileExplorer.h" - -EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID; - -/// -/// File system selection menu -/// -MENU_OPTION mFsOptionMenu = { - MENU_OPTION_SIGNATURE, - {NULL}, - 0, - FALSE -}; - -FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = { - FILE_EXPLORER_CALLBACK_DATA_SIGNATURE, - NULL, - NULL, - { - LibExtractConfig, - LibRouteConfig, - LibCallback - }, - NULL, - &mFsOptionMenu, - 0 -}; - -HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath; - -HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = { - { - { - HARDWARE_DEVICE_PATH, - HW_VENDOR_DP, - { - (UINT8) (sizeof (VENDOR_DEVICE_PATH)), - (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) - } - }, - // - // Will be replace with gEfiCallerIdGuid in code. - // - { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } - }, - { - END_DEVICE_PATH_TYPE, - END_ENTIRE_DEVICE_PATH_SUBTYPE, - { - (UINT8) (END_DEVICE_PATH_LENGTH), - (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) - } - } -}; - -VOID *mLibStartOpCodeHandle = NULL; -VOID *mLibEndOpCodeHandle = NULL; -EFI_IFR_GUID_LABEL *mLibStartLabel = NULL; -EFI_IFR_GUID_LABEL *mLibEndLabel = NULL; - -/** - This function allows a caller to extract the current configuration for one - or more named elements from the target driver. - - - @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. - @param Request A null-terminated Unicode string in 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; - - 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 (gFileExplorerPrivate.ChooseHandler != NULL) { - NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath); - } - - if (NeedExit) { - *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; - } - } - } else if (Action == EFI_BROWSER_ACTION_CHANGING) { - if (Value == NULL) { - return EFI_INVALID_PARAMETER; - } - - if (QuestionId >= FILE_OPTION_OFFSET) { - Status = LibUpdateFileExplorer (QuestionId); - if (EFI_ERROR (Status)) { - return Status; - } - } - } - - return EFI_SUCCESS; -} - -/** - Create a menu entry by given menu type. - - @retval NULL If failed to create the menu. - @return the new menu entry. - -**/ -MENU_ENTRY * -LibCreateMenuEntry ( - VOID - ) -{ - MENU_ENTRY *MenuEntry; - - // - // Create new menu entry - // - MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY)); - if (MenuEntry == NULL) { - return NULL; - } - - MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT)); - if (MenuEntry->VariableContext == NULL) { - FreePool (MenuEntry); - return NULL; - } - - MenuEntry->Signature = MENU_ENTRY_SIGNATURE; - return MenuEntry; -} - - -/** - Get the Menu Entry from the list in Menu Entry List. - - If MenuNumber is great or equal to the number of Menu - Entry in the list, then ASSERT. - - @param MenuOption The Menu Entry List to read the menu entry. - @param MenuNumber The index of Menu Entry. - - @return The Menu Entry. - -**/ -MENU_ENTRY * -LibGetMenuEntry ( - MENU_OPTION *MenuOption, - UINTN MenuNumber - ) -{ - MENU_ENTRY *NewMenuEntry; - UINTN Index; - LIST_ENTRY *List; - - ASSERT (MenuNumber < MenuOption->MenuNumber); - - List = MenuOption->Head.ForwardLink; - for (Index = 0; Index < MenuNumber; Index++) { - List = List->ForwardLink; - } - - NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE); - - return NewMenuEntry; -} - -/** - Free up all resource allocated for a BM_MENU_ENTRY. - - @param MenuEntry A pointer to BM_MENU_ENTRY. - -**/ -VOID -LibDestroyMenuEntry ( - MENU_ENTRY *MenuEntry - ) -{ - FILE_CONTEXT *FileContext; - - FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; - - if (!FileContext->IsRoot) { - FreePool (FileContext->DevicePath); - } else { - if (FileContext->FileHandle != NULL) { - FileContext->FileHandle->Close (FileContext->FileHandle); - } - } - - if (FileContext->FileName != NULL) { - FreePool (FileContext->FileName); - } - - FreePool (FileContext); - - FreePool (MenuEntry->DisplayString); - if (MenuEntry->HelpString != NULL) { - FreePool (MenuEntry->HelpString); - } - - FreePool (MenuEntry); -} - - -/** - Free resources allocated in Allocate Rountine. - - @param FreeMenu Menu to be freed -**/ -VOID -LibFreeMenu ( - MENU_OPTION *FreeMenu - ) -{ - MENU_ENTRY *MenuEntry; - while (!IsListEmpty (&FreeMenu->Head)) { - MenuEntry = CR ( - FreeMenu->Head.ForwardLink, - MENU_ENTRY, - Link, - MENU_ENTRY_SIGNATURE - ); - RemoveEntryList (&MenuEntry->Link); - LibDestroyMenuEntry (MenuEntry); - } - FreeMenu->MenuNumber = 0; -} - -/** - - Function opens and returns a file handle to the root directory of a volume. - - @param DeviceHandle A handle for a device - - @return A valid file handle or NULL is returned - -**/ -EFI_FILE_HANDLE -LibOpenRoot ( - IN EFI_HANDLE DeviceHandle - ) -{ - EFI_STATUS Status; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; - EFI_FILE_HANDLE File; - - File = NULL; - - // - // File the file system interface to the device - // - Status = gBS->HandleProtocol ( - DeviceHandle, - &gEfiSimpleFileSystemProtocolGuid, - (VOID *) &Volume - ); - - // - // Open the root directory of the volume - // - if (!EFI_ERROR (Status)) { - Status = Volume->OpenVolume ( - Volume, - &File - ); - } - // - // Done - // - return EFI_ERROR (Status) ? NULL : File; -} - -/** - This function converts an input device structure to a Unicode string. - - @param DevPath A pointer to the device path structure. - - @return A new allocated Unicode string that represents the device path. - -**/ -CHAR16 * -LibDevicePathToStr ( - IN EFI_DEVICE_PATH_PROTOCOL *DevPath - ) -{ - EFI_STATUS Status; - CHAR16 *ToText; - EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; - - if (DevPath == NULL) { - return NULL; - } - - Status = gBS->LocateProtocol ( - &gEfiDevicePathToTextProtocolGuid, - NULL, - (VOID **) &DevPathToText - ); - ASSERT_EFI_ERROR (Status); - ToText = DevPathToText->ConvertDevicePathToText ( - DevPath, - FALSE, - TRUE - ); - ASSERT (ToText != NULL); - - return ToText; -} - -/** - Duplicate a string. - - @param Src The source. - - @return A new string which is duplicated copy of the source. - @retval NULL If there is not enough memory. - -**/ -CHAR16 * -LibStrDuplicate ( - IN CHAR16 *Src - ) -{ - CHAR16 *Dest; - UINTN Size; - - Size = StrSize (Src); - Dest = AllocateZeroPool (Size); - ASSERT (Dest != NULL); - if (Dest != NULL) { - CopyMem (Dest, Src, Size); - } - - return Dest; -} - -/** - - Function gets the file information from an open file descriptor, and stores it - in a buffer allocated from pool. - - @param FHand File Handle. - @param InfoType Info type need to get. - - @retval A pointer to a buffer with file information or NULL is returned - -**/ -VOID * -LibFileInfo ( - IN EFI_FILE_HANDLE FHand, - IN EFI_GUID *InfoType - ) -{ - EFI_STATUS Status; - EFI_FILE_INFO *Buffer; - UINTN BufferSize; - - Buffer = NULL; - BufferSize = 0; - - Status = FHand->GetInfo ( - FHand, - InfoType, - &BufferSize, - Buffer - ); - if (Status == EFI_BUFFER_TOO_SMALL) { - Buffer = AllocatePool (BufferSize); - ASSERT (Buffer != NULL); - } - - Status = FHand->GetInfo ( - FHand, - InfoType, - &BufferSize, - Buffer - ); - - return Buffer; -} - -/** - - Get file type base on the file name. - Just cut the file name, from the ".". eg ".efi" - - @param FileName File need to be checked. - - @retval the file type string. - -**/ -CHAR16* -LibGetTypeFromName ( - IN CHAR16 *FileName - ) -{ - UINTN Index; - - Index = StrLen (FileName) - 1; - while ((FileName[Index] != L'.') && (Index != 0)) { - Index--; - } - - return Index == 0 ? NULL : &FileName[Index]; -} - -/** - Converts the unicode character of the string from uppercase to lowercase. - This is a internal function. - - @param ConfigString String to be converted - -**/ -VOID -LibToLowerString ( - IN CHAR16 *String - ) -{ - CHAR16 *TmpStr; - - for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) { - if (*TmpStr >= L'A' && *TmpStr <= L'Z') { - *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a'); - } - } -} - -/** - - Check whether current FileName point to a valid - Efi Image File. - - @param FileName File need to be checked. - - @retval TRUE Is Efi Image - @retval FALSE Not a valid Efi Image - -**/ -BOOLEAN -LibIsSupportedFileType ( - IN UINT16 *FileName - ) -{ - CHAR16 *InputFileType; - CHAR16 *TmpStr; - BOOLEAN IsSupported; - - if (gFileExplorerPrivate.FileType == NULL) { - return TRUE; - } - - InputFileType = LibGetTypeFromName (FileName); - // - // If the file not has *.* style, always return TRUE. - // - if (InputFileType == NULL) { - return TRUE; - } - - TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType); - LibToLowerString(TmpStr); - - IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE); - - FreePool (TmpStr); - return IsSupported; -} - -/** - - Append file name to existing file name. - - @param Str1 The existing file name - @param Str2 The file name to be appended - - @return Allocate a new string to hold the appended result. - Caller is responsible to free the returned string. - -**/ -CHAR16 * -LibAppendFileName ( - IN CHAR16 *Str1, - IN CHAR16 *Str2 - ) -{ - UINTN Size1; - UINTN Size2; - UINTN MaxLen; - CHAR16 *Str; - CHAR16 *TmpStr; - CHAR16 *Ptr; - CHAR16 *LastSlash; - - Size1 = StrSize (Str1); - Size2 = StrSize (Str2); - MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16); - Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); - ASSERT (Str != NULL); - - TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); - ASSERT (TmpStr != NULL); - - StrCpyS (Str, MaxLen, Str1); - if (!((*Str == '\\') && (*(Str + 1) == 0))) { - StrCatS (Str, MaxLen, L"\\"); - } - - StrCatS (Str, MaxLen, Str2); - - Ptr = Str; - LastSlash = Str; - while (*Ptr != 0) { - if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { - // - // Convert "\Name\..\" to "\" - // DO NOT convert the .. if it is at the end of the string. This will - // break the .. behavior in changing directories. - // - - // - // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings - // that overlap. - // - StrCpyS (TmpStr, MaxLen, Ptr + 3); - StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr); - Ptr = LastSlash; - } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { - // - // Convert a "\.\" to a "\" - // - - // - // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings - // that overlap. - // - StrCpyS (TmpStr, MaxLen, Ptr + 2); - StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr); - Ptr = LastSlash; - } else if (*Ptr == '\\') { - LastSlash = Ptr; - } - - Ptr++; - } - - FreePool (TmpStr); - - return Str; -} - -/** - This function build the FsOptionMenu list which records all - available file system in the system. They includes all instances - of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM. - - - @retval EFI_SUCCESS Success find the file system - @retval EFI_OUT_OF_RESOURCES Can not create menu entry - -**/ -EFI_STATUS -LibFindFileSystem ( - VOID - ) -{ - UINTN NoSimpleFsHandles; - UINTN NoLoadFileHandles; - EFI_HANDLE *SimpleFsHandle; - EFI_HANDLE *LoadFileHandle; - UINT16 *VolumeLabel; - UINTN Index; - EFI_STATUS Status; - MENU_ENTRY *MenuEntry; - FILE_CONTEXT *FileContext; - UINTN OptionNumber; - EFI_FILE_SYSTEM_VOLUME_LABEL *Info; - - NoSimpleFsHandles = 0; - NoLoadFileHandles = 0; - OptionNumber = 0; - - // - // Locate Handles that support Simple File System protocol - // - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiSimpleFileSystemProtocolGuid, - NULL, - &NoSimpleFsHandles, - &SimpleFsHandle - ); - if (!EFI_ERROR (Status)) { - // - // Find all the instances of the File System prototocol - // - for (Index = 0; Index < NoSimpleFsHandles; Index++) { - // - // Allocate pool for this load option - // - MenuEntry = LibCreateMenuEntry (); - if (NULL == MenuEntry) { - FreePool (SimpleFsHandle); - return EFI_OUT_OF_RESOURCES; - } - - FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; - FileContext->DeviceHandle = SimpleFsHandle[Index]; - FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle); - if (FileContext->FileHandle == NULL) { - LibDestroyMenuEntry (MenuEntry); - continue; - } - - MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle)); - FileContext->FileName = LibStrDuplicate (L"\\"); - FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName); - FileContext->IsDir = TRUE; - FileContext->IsRoot = TRUE; - - // - // Get current file system's Volume Label - // - Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid); - if (Info == NULL) { - VolumeLabel = L"NO FILE SYSTEM INFO"; - } else { - if (Info->VolumeLabel == NULL) { - VolumeLabel = L"NULL VOLUME LABEL"; - } else { - VolumeLabel = Info->VolumeLabel; - if (*VolumeLabel == 0x0000) { - VolumeLabel = L"NO VOLUME LABEL"; - } - } - } - MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); - ASSERT (MenuEntry->DisplayString != NULL); - UnicodeSPrint ( - MenuEntry->DisplayString, - MAX_CHAR, - L"%s, [%s]", - VolumeLabel, - MenuEntry->HelpString - ); - MenuEntry->DisplayStringToken = HiiSetString ( - gFileExplorerPrivate.FeHiiHandle, - 0, - MenuEntry->DisplayString, - NULL - ); - FreePool (Info); - - OptionNumber++; - InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); - } - } - - if (NoSimpleFsHandles != 0) { - FreePool (SimpleFsHandle); - } - - // - // Searching for handles that support Load File protocol - // - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiLoadFileProtocolGuid, - NULL, - &NoLoadFileHandles, - &LoadFileHandle - ); - - if (!EFI_ERROR (Status)) { - for (Index = 0; Index < NoLoadFileHandles; Index++) { - MenuEntry = LibCreateMenuEntry (); - if (NULL == MenuEntry) { - FreePool (LoadFileHandle); - return EFI_OUT_OF_RESOURCES; - } - - FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; - FileContext->DeviceHandle = LoadFileHandle[Index]; - FileContext->IsRoot = TRUE; - - FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle); - FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath); - - MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath); - MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); - ASSERT (MenuEntry->DisplayString != NULL); - UnicodeSPrint ( - MenuEntry->DisplayString, - MAX_CHAR, - L"Load File [%s]", - MenuEntry->HelpString - ); - MenuEntry->DisplayStringToken = HiiSetString ( - gFileExplorerPrivate.FeHiiHandle, - 0, - MenuEntry->DisplayString, - NULL - ); - - OptionNumber++; - InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); - } - } - - if (NoLoadFileHandles != 0) { - FreePool (LoadFileHandle); - } - - gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; - - return EFI_SUCCESS; -} - -/** - Find the file handle from the input menu info. - - @param MenuEntry Input Menu info. - @param RetFileHandle Return the file handle for the input device path. - - @retval EFI_SUCESS Find the file handle success. - @retval Other Find the file handle failure. -**/ -EFI_STATUS -LibGetFileHandleFromMenu ( - IN MENU_ENTRY *MenuEntry, - OUT EFI_FILE_HANDLE *RetFileHandle - ) -{ - EFI_FILE_HANDLE Dir; - EFI_FILE_HANDLE NewDir; - FILE_CONTEXT *FileContext; - EFI_STATUS Status; - - FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; - Dir = FileContext->FileHandle; - - // - // Open current directory to get files from it - // - Status = Dir->Open ( - Dir, - &NewDir, - FileContext->FileName, - EFI_FILE_READ_ONLY, - 0 - ); - if (EFI_ERROR (Status)) { - return Status; - } - - if (!FileContext->IsRoot) { - Dir->Close (Dir); - } - - *RetFileHandle = NewDir; - - return EFI_SUCCESS; -} - -/** - Find the file handle from the input device path info. - - @param RootDirectory Device path info. - @param RetFileHandle Return the file handle for the input device path. - @param ParentFileName Parent file name. - @param DeviceHandle Driver handle for this partition. - - @retval EFI_SUCESS Find the file handle success. - @retval Other Find the file handle failure. -**/ -EFI_STATUS -LibGetFileHandleFromDevicePath ( - IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, - OUT EFI_FILE_HANDLE *RetFileHandle, - OUT UINT16 **ParentFileName, - OUT EFI_HANDLE *DeviceHandle - ) -{ - EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; - EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode; - EFI_STATUS Status; - EFI_HANDLE Handle; - EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; - EFI_FILE_HANDLE FileHandle; - EFI_FILE_HANDLE LastHandle; - CHAR16 *TempPath; - - *ParentFileName = NULL; - - // - // Attempt to access the file via a file system interface - // - DevicePathNode = RootDirectory; - Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle); - if (EFI_ERROR (Status)) { - return Status; - } - - Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume); - if (EFI_ERROR (Status)) { - return Status; - } - - // - // Open the Volume to get the File System handle - // - Status = Volume->OpenVolume (Volume, &FileHandle); - if (EFI_ERROR (Status)) { - return Status; - } - - *DeviceHandle = Handle; - - if (IsDevicePathEnd(DevicePathNode)) { - *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\"); - *RetFileHandle = FileHandle; - return EFI_SUCCESS; - } - - // - // Duplicate the device path to avoid the access to unaligned device path node. - // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH - // nodes, It assures the fields in device path nodes are 2 byte aligned. - // - TempDevicePathNode = DuplicateDevicePath (DevicePathNode); - if (TempDevicePathNode == NULL) { - - // - // Setting Status to an EFI_ERROR value will cause the rest of - // the file system support below to be skipped. - // - Status = EFI_OUT_OF_RESOURCES; - } - - // - // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the - // directory information and filename can be seperate. The goal is to inch - // our way down each device path node and close the previous node - // - DevicePathNode = TempDevicePathNode; - while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) { - if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH || - DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) { - Status = EFI_UNSUPPORTED; - goto Done; - } - - LastHandle = FileHandle; - FileHandle = NULL; - - Status = LastHandle->Open ( - LastHandle, - &FileHandle, - ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName, - EFI_FILE_MODE_READ, - 0 - ); - if (*ParentFileName == NULL) { - *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); - } else { - TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); - FreePool (*ParentFileName); - *ParentFileName = TempPath; - } - - // - // Close the previous node - // - LastHandle->Close (LastHandle); - - DevicePathNode = NextDevicePathNode (DevicePathNode); - } - - if (EFI_ERROR (Status)) { - goto Done; - } - - *RetFileHandle = FileHandle; - - Status = EFI_SUCCESS; - -Done: - if (TempDevicePathNode != NULL) { - FreePool (TempDevicePathNode); - } - - if ((FileHandle != NULL) && (EFI_ERROR (Status))) { - FileHandle->Close (FileHandle); - } - - return Status; -} - -/** - Find files under current directory. - - All files and sub-directories in current directory - will be stored in DirectoryMenu for future use. - - @param FileHandle Parent file handle. - @param FileName Parent file name. - @param DeviceHandle Driver handle for this partition. - - @retval EFI_SUCCESS Get files from current dir successfully. - @return Other value if can't get files from current dir. - -**/ -EFI_STATUS -LibFindFiles ( - IN EFI_FILE_HANDLE FileHandle, - IN UINT16 *FileName, - IN EFI_HANDLE DeviceHandle - ) -{ - EFI_FILE_INFO *DirInfo; - UINTN BufferSize; - UINTN DirBufferSize; - MENU_ENTRY *NewMenuEntry; - FILE_CONTEXT *NewFileContext; - UINTN Pass; - EFI_STATUS Status; - UINTN OptionNumber; - - OptionNumber = 0; - - DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; - DirInfo = AllocateZeroPool (DirBufferSize); - if (DirInfo == NULL) { - return EFI_OUT_OF_RESOURCES; - } - - // - // Get all files in current directory - // Pass 1 to get Directories - // Pass 2 to get files that are EFI images - // - for (Pass = 1; Pass <= 2; Pass++) { - FileHandle->SetPosition (FileHandle, 0); - for (;;) { - BufferSize = DirBufferSize; - Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo); - if (EFI_ERROR (Status) || BufferSize == 0) { - break; - } - - if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || - ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) - ) { - // - // Pass 1 is for Directories - // Pass 2 is for file names - // - continue; - } - - if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) { - // - // Slip file unless it is a directory entry or a .EFI file - // - continue; - } - - NewMenuEntry = LibCreateMenuEntry (); - if (NULL == NewMenuEntry) { - return EFI_OUT_OF_RESOURCES; - } - - NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; - NewFileContext->DeviceHandle = DeviceHandle; - NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName); - NewFileContext->FileHandle = FileHandle; - NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName); - NewMenuEntry->HelpString = NULL; - NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); - - if (NewFileContext->IsDir) { - BufferSize = StrLen (DirInfo->FileName) * 2 + 6; - NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); - UnicodeSPrint ( - NewMenuEntry->DisplayString, - BufferSize, - L"<%s>", - DirInfo->FileName - ); - } else { - NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName); - } - - NewMenuEntry->DisplayStringToken = HiiSetString ( - gFileExplorerPrivate.FeHiiHandle, - 0, - NewMenuEntry->DisplayString, - NULL - ); - - NewFileContext->IsRoot = FALSE; - - OptionNumber++; - InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link); - } - } - - gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; - - FreePool (DirInfo); - - return EFI_SUCCESS; -} - -/** - Refresh the global UpdateData structure. - -**/ -VOID -LibRefreshUpdateData ( - VOID - ) -{ - // - // Free current updated date - // - if (mLibStartOpCodeHandle != NULL) { - HiiFreeOpCodeHandle (mLibStartOpCodeHandle); - } - if (mLibEndOpCodeHandle != NULL) { - HiiFreeOpCodeHandle (mLibEndOpCodeHandle); - } - - // - // Create new OpCode Handle - // - mLibStartOpCodeHandle = HiiAllocateOpCodeHandle (); - mLibEndOpCodeHandle = HiiAllocateOpCodeHandle (); - - // - // Create Hii Extend Label OpCode as the start opcode - // - mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( - mLibStartOpCodeHandle, - &gEfiIfrTianoGuid, - NULL, - sizeof (EFI_IFR_GUID_LABEL) - ); - mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; - - mLibStartLabel->Number = FORM_FILE_EXPLORER_ID; - - // - // Create Hii Extend Label OpCode as the start opcode - // - mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( - mLibEndOpCodeHandle, - &gEfiIfrTianoGuid, - NULL, - sizeof (EFI_IFR_GUID_LABEL) - ); - mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; - - mLibEndLabel->Number = LABEL_END; -} - -/** - - Update the File Explore page. - -**/ -VOID -LibUpdateFileExplorePage ( - VOID - ) -{ - UINTN Index; - MENU_ENTRY *NewMenuEntry; - FILE_CONTEXT *NewFileContext; - MENU_OPTION *MenuOption; - - NewMenuEntry = NULL; - NewFileContext = NULL; - - LibRefreshUpdateData (); - MenuOption = gFileExplorerPrivate.FsOptionMenu; - - for (Index = 0; Index < MenuOption->MenuNumber; Index++) { - NewMenuEntry = LibGetMenuEntry (MenuOption, Index); - NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; - - if (!NewFileContext->IsDir) { - // - // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. - // - HiiCreateActionOpCode ( - mLibStartOpCodeHandle, - (UINT16) (FILE_OPTION_OFFSET + Index), - NewMenuEntry->DisplayStringToken, - STRING_TOKEN (STR_NULL_STRING), - EFI_IFR_FLAG_CALLBACK, - 0 - ); - } else { - // - // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState. - // - HiiCreateGotoOpCode ( - mLibStartOpCodeHandle, - FORM_FILE_EXPLORER_ID, - NewMenuEntry->DisplayStringToken, - STRING_TOKEN (STR_NULL_STRING), - EFI_IFR_FLAG_CALLBACK, - (UINT16) (FILE_OPTION_OFFSET + Index) - ); - } - } - - HiiUpdateForm ( - gFileExplorerPrivate.FeHiiHandle, - &FileExplorerGuid, - FORM_FILE_EXPLORER_ID, - mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID - mLibEndOpCodeHandle // LABEL_END - ); -} - -/** - Update the file explower page with the refershed file system. - - @param KeyValue Key value to identify the type of data to expect. - - @retval EFI_SUCCESS Update the file explorer form success. - @retval other errors Error occur when parse one directory. - -**/ -EFI_STATUS -LibUpdateFileExplorer ( - IN UINT16 KeyValue - ) -{ - UINT16 FileOptionMask; - MENU_ENTRY *NewMenuEntry; - FILE_CONTEXT *NewFileContext; - EFI_STATUS Status; - EFI_FILE_HANDLE FileHandle; - - Status = EFI_SUCCESS; - FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); - NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); - NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; - - if (NewFileContext->IsDir) { - RemoveEntryList (&NewMenuEntry->Link); - LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); - LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle); - Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle); - if (!EFI_ERROR (Status)) { - LibUpdateFileExplorePage (); - } else { - LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); - } - LibDestroyMenuEntry (NewMenuEntry); - } - - return Status; -} - -/** - Get the device path info saved in the menu structure. - - @param KeyValue Key value to identify the type of data to expect. - -**/ -VOID -LibGetDevicePath ( - IN UINT16 KeyValue - ) -{ - UINT16 FileOptionMask; - MENU_ENTRY *NewMenuEntry; - FILE_CONTEXT *NewFileContext; - - FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); - - NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); - - NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; - - if (gFileExplorerPrivate.RetDevicePath != NULL) { - FreePool (gFileExplorerPrivate.RetDevicePath); - } - gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath); -} - -/** - Choose a file in the specified directory. - - If user input NULL for the RootDirectory, will choose file in the system. - - If user input *File != NULL, function will return the allocate device path - info for the choosed file, caller has to free the memory after use it. - - @param RootDirectory Pointer to the root directory. - @param FileType The file type need to choose. - @param ChooseHandler Function pointer to the extra task need to do - after choose one file. - @param File Return the device path for the last time chosed file. - - @retval EFI_SUCESS Choose file success. - @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL - One of them must not NULL. - @retval Other errors Choose file failed. -**/ -EFI_STATUS -EFIAPI -ChooseFile ( - IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, - IN CHAR16 *FileType, OPTIONAL - IN CHOOSE_HANDLER ChooseHandler, OPTIONAL - OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL - ) -{ - EFI_FILE_HANDLE FileHandle; - EFI_STATUS Status; - UINT16 *FileName; - EFI_HANDLE DeviceHandle; - - if ((ChooseHandler == NULL) && (File == NULL)) { - return EFI_INVALID_PARAMETER; - } - - FileName = NULL; - - gFileExplorerPrivate.RetDevicePath = NULL; - gFileExplorerPrivate.ChooseHandler = ChooseHandler; - if (FileType != NULL) { - gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType); - LibToLowerString(gFileExplorerPrivate.FileType); - } else { - gFileExplorerPrivate.FileType = NULL; - } - - if (RootDirectory == NULL) { - Status = LibFindFileSystem(); - } else { - Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle); - if (EFI_ERROR (Status)) { - goto Done; - } - - Status = LibFindFiles (FileHandle, FileName, DeviceHandle); - } - if (EFI_ERROR (Status)) { - goto Done; - } - - LibUpdateFileExplorePage(); - - gFileExplorerPrivate.FormBrowser2->SendForm ( - gFileExplorerPrivate.FormBrowser2, - &gFileExplorerPrivate.FeHiiHandle, - 1, - &FileExplorerGuid, - 0, - NULL, - NULL - ); - -Done: - if ((Status == EFI_SUCCESS) && (File != NULL)) { - *File = gFileExplorerPrivate.RetDevicePath; - } else if (gFileExplorerPrivate.RetDevicePath != NULL) { - FreePool (gFileExplorerPrivate.RetDevicePath); - } - - if (gFileExplorerPrivate.FileType != NULL) { - FreePool (gFileExplorerPrivate.FileType); - } - - LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); - - if (FileName != NULL) { - FreePool (FileName); - } - - return Status; -} - -/** - - Install Boot Manager Menu driver. - - @param ImageHandle The image handle. - @param SystemTable The system table. - - @retval EFI_SUCEESS Install File explorer library success. - -**/ -EFI_STATUS -EFIAPI -FileExplorerLibConstructor ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - EFI_STATUS Status; - - gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); - ASSERT (gHiiVendorDevicePath != NULL); - CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid); - - // - // Install Device Path Protocol and Config Access protocol to driver handle - // - Status = gBS->InstallMultipleProtocolInterfaces ( - &gFileExplorerPrivate.FeDriverHandle, - &gEfiDevicePathProtocolGuid, - gHiiVendorDevicePath, - &gEfiHiiConfigAccessProtocolGuid, - &gFileExplorerPrivate.FeConfigAccess, - NULL - ); - 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); - - 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); - - Status = gBS->UninstallMultipleProtocolInterfaces ( - gFileExplorerPrivate.FeDriverHandle, - &gEfiDevicePathProtocolGuid, - gHiiVendorDevicePath, - &gEfiHiiConfigAccessProtocolGuid, - &gFileExplorerPrivate.FeConfigAccess, - NULL - ); - ASSERT_EFI_ERROR (Status); - - HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle); - - FreePool (gHiiVendorDevicePath); - - return EFI_SUCCESS; -} - +/** @file +File explorer related functions. + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+This program and the accompanying materials are licensed and made available under +the terms and conditions of the BSD License that accompanies this distribution. +The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php. + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + + +#include "FileExplorer.h" + +EFI_GUID FileExplorerGuid = EFI_FILE_EXPLORE_FORMSET_GUID; + +/// +/// File system selection menu +/// +MENU_OPTION mFsOptionMenu = { + MENU_OPTION_SIGNATURE, + {NULL}, + 0, + FALSE +}; + +FILE_EXPLORER_CALLBACK_DATA gFileExplorerPrivate = { + FILE_EXPLORER_CALLBACK_DATA_SIGNATURE, + NULL, + NULL, + { + LibExtractConfig, + LibRouteConfig, + LibCallback + }, + NULL, + &mFsOptionMenu, + 0 +}; + +HII_VENDOR_DEVICE_PATH *gHiiVendorDevicePath; + +HII_VENDOR_DEVICE_PATH FeHiiVendorDevicePath = { + { + { + HARDWARE_DEVICE_PATH, + HW_VENDOR_DP, + { + (UINT8) (sizeof (VENDOR_DEVICE_PATH)), + (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) + } + }, + // + // Will be replace with gEfiCallerIdGuid in code. + // + { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } } + }, + { + END_DEVICE_PATH_TYPE, + END_ENTIRE_DEVICE_PATH_SUBTYPE, + { + (UINT8) (END_DEVICE_PATH_LENGTH), + (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) + } + } +}; + +VOID *mLibStartOpCodeHandle = NULL; +VOID *mLibEndOpCodeHandle = NULL; +EFI_IFR_GUID_LABEL *mLibStartLabel = NULL; +EFI_IFR_GUID_LABEL *mLibEndLabel = NULL; + +/** + This function allows a caller to extract the current configuration for one + or more named elements from the target driver. + + + @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. + @param Request A null-terminated Unicode string in 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; + + 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 (gFileExplorerPrivate.ChooseHandler != NULL) { + NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath); + } + + if (NeedExit) { + *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; + } + } + } else if (Action == EFI_BROWSER_ACTION_CHANGING) { + if (Value == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (QuestionId >= FILE_OPTION_OFFSET) { + Status = LibUpdateFileExplorer (QuestionId); + if (EFI_ERROR (Status)) { + return Status; + } + } + } + + return EFI_SUCCESS; +} + +/** + Create a menu entry by given menu type. + + @retval NULL If failed to create the menu. + @return the new menu entry. + +**/ +MENU_ENTRY * +LibCreateMenuEntry ( + VOID + ) +{ + MENU_ENTRY *MenuEntry; + + // + // Create new menu entry + // + MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY)); + if (MenuEntry == NULL) { + return NULL; + } + + MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT)); + if (MenuEntry->VariableContext == NULL) { + FreePool (MenuEntry); + return NULL; + } + + MenuEntry->Signature = MENU_ENTRY_SIGNATURE; + return MenuEntry; +} + + +/** + Get the Menu Entry from the list in Menu Entry List. + + If MenuNumber is great or equal to the number of Menu + Entry in the list, then ASSERT. + + @param MenuOption The Menu Entry List to read the menu entry. + @param MenuNumber The index of Menu Entry. + + @return The Menu Entry. + +**/ +MENU_ENTRY * +LibGetMenuEntry ( + MENU_OPTION *MenuOption, + UINTN MenuNumber + ) +{ + MENU_ENTRY *NewMenuEntry; + UINTN Index; + LIST_ENTRY *List; + + ASSERT (MenuNumber < MenuOption->MenuNumber); + + List = MenuOption->Head.ForwardLink; + for (Index = 0; Index < MenuNumber; Index++) { + List = List->ForwardLink; + } + + NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE); + + return NewMenuEntry; +} + +/** + Free up all resource allocated for a BM_MENU_ENTRY. + + @param MenuEntry A pointer to BM_MENU_ENTRY. + +**/ +VOID +LibDestroyMenuEntry ( + MENU_ENTRY *MenuEntry + ) +{ + FILE_CONTEXT *FileContext; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + + if (!FileContext->IsRoot) { + FreePool (FileContext->DevicePath); + } else { + if (FileContext->FileHandle != NULL) { + FileContext->FileHandle->Close (FileContext->FileHandle); + } + } + + if (FileContext->FileName != NULL) { + FreePool (FileContext->FileName); + } + + FreePool (FileContext); + + FreePool (MenuEntry->DisplayString); + if (MenuEntry->HelpString != NULL) { + FreePool (MenuEntry->HelpString); + } + + FreePool (MenuEntry); +} + + +/** + Free resources allocated in Allocate Rountine. + + @param FreeMenu Menu to be freed +**/ +VOID +LibFreeMenu ( + MENU_OPTION *FreeMenu + ) +{ + MENU_ENTRY *MenuEntry; + while (!IsListEmpty (&FreeMenu->Head)) { + MenuEntry = CR ( + FreeMenu->Head.ForwardLink, + MENU_ENTRY, + Link, + MENU_ENTRY_SIGNATURE + ); + RemoveEntryList (&MenuEntry->Link); + LibDestroyMenuEntry (MenuEntry); + } + FreeMenu->MenuNumber = 0; +} + +/** + + Function opens and returns a file handle to the root directory of a volume. + + @param DeviceHandle A handle for a device + + @return A valid file handle or NULL is returned + +**/ +EFI_FILE_HANDLE +LibOpenRoot ( + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE File; + + File = NULL; + + // + // File the file system interface to the device + // + Status = gBS->HandleProtocol ( + DeviceHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID *) &Volume + ); + + // + // Open the root directory of the volume + // + if (!EFI_ERROR (Status)) { + Status = Volume->OpenVolume ( + Volume, + &File + ); + } + // + // Done + // + return EFI_ERROR (Status) ? NULL : File; +} + +/** + This function converts an input device structure to a Unicode string. + + @param DevPath A pointer to the device path structure. + + @return A new allocated Unicode string that represents the device path. + +**/ +CHAR16 * +LibDevicePathToStr ( + IN EFI_DEVICE_PATH_PROTOCOL *DevPath + ) +{ + EFI_STATUS Status; + CHAR16 *ToText; + EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText; + + if (DevPath == NULL) { + return NULL; + } + + Status = gBS->LocateProtocol ( + &gEfiDevicePathToTextProtocolGuid, + NULL, + (VOID **) &DevPathToText + ); + ASSERT_EFI_ERROR (Status); + ToText = DevPathToText->ConvertDevicePathToText ( + DevPath, + FALSE, + TRUE + ); + ASSERT (ToText != NULL); + + return ToText; +} + +/** + Duplicate a string. + + @param Src The source. + + @return A new string which is duplicated copy of the source. + @retval NULL If there is not enough memory. + +**/ +CHAR16 * +LibStrDuplicate ( + IN CHAR16 *Src + ) +{ + CHAR16 *Dest; + UINTN Size; + + Size = StrSize (Src); + Dest = AllocateZeroPool (Size); + ASSERT (Dest != NULL); + if (Dest != NULL) { + CopyMem (Dest, Src, Size); + } + + return Dest; +} + +/** + + Function gets the file information from an open file descriptor, and stores it + in a buffer allocated from pool. + + @param FHand File Handle. + @param InfoType Info type need to get. + + @retval A pointer to a buffer with file information or NULL is returned + +**/ +VOID * +LibFileInfo ( + IN EFI_FILE_HANDLE FHand, + IN EFI_GUID *InfoType + ) +{ + EFI_STATUS Status; + EFI_FILE_INFO *Buffer; + UINTN BufferSize; + + Buffer = NULL; + BufferSize = 0; + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + if (Status == EFI_BUFFER_TOO_SMALL) { + Buffer = AllocatePool (BufferSize); + ASSERT (Buffer != NULL); + } + + Status = FHand->GetInfo ( + FHand, + InfoType, + &BufferSize, + Buffer + ); + + return Buffer; +} + +/** + + Get file type base on the file name. + Just cut the file name, from the ".". eg ".efi" + + @param FileName File need to be checked. + + @retval the file type string. + +**/ +CHAR16* +LibGetTypeFromName ( + IN CHAR16 *FileName + ) +{ + UINTN Index; + + Index = StrLen (FileName) - 1; + while ((FileName[Index] != L'.') && (Index != 0)) { + Index--; + } + + return Index == 0 ? NULL : &FileName[Index]; +} + +/** + Converts the unicode character of the string from uppercase to lowercase. + This is a internal function. + + @param ConfigString String to be converted + +**/ +VOID +LibToLowerString ( + IN CHAR16 *String + ) +{ + CHAR16 *TmpStr; + + for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) { + if (*TmpStr >= L'A' && *TmpStr <= L'Z') { + *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a'); + } + } +} + +/** + + Check whether current FileName point to a valid + Efi Image File. + + @param FileName File need to be checked. + + @retval TRUE Is Efi Image + @retval FALSE Not a valid Efi Image + +**/ +BOOLEAN +LibIsSupportedFileType ( + IN UINT16 *FileName + ) +{ + CHAR16 *InputFileType; + CHAR16 *TmpStr; + BOOLEAN IsSupported; + + if (gFileExplorerPrivate.FileType == NULL) { + return TRUE; + } + + InputFileType = LibGetTypeFromName (FileName); + // + // If the file not has *.* style, always return TRUE. + // + if (InputFileType == NULL) { + return TRUE; + } + + TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType); + LibToLowerString(TmpStr); + + IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE); + + FreePool (TmpStr); + return IsSupported; +} + +/** + + Append file name to existing file name. + + @param Str1 The existing file name + @param Str2 The file name to be appended + + @return Allocate a new string to hold the appended result. + Caller is responsible to free the returned string. + +**/ +CHAR16 * +LibAppendFileName ( + IN CHAR16 *Str1, + IN CHAR16 *Str2 + ) +{ + UINTN Size1; + UINTN Size2; + UINTN MaxLen; + CHAR16 *Str; + CHAR16 *TmpStr; + CHAR16 *Ptr; + CHAR16 *LastSlash; + + Size1 = StrSize (Str1); + Size2 = StrSize (Str2); + MaxLen = (Size1 + Size2 + sizeof (CHAR16))/ sizeof (CHAR16); + Str = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (Str != NULL); + + TmpStr = AllocateZeroPool (Size1 + Size2 + sizeof (CHAR16)); + ASSERT (TmpStr != NULL); + + StrCpyS (Str, MaxLen, Str1); + if (!((*Str == '\\') && (*(Str + 1) == 0))) { + StrCatS (Str, MaxLen, L"\\"); + } + + StrCatS (Str, MaxLen, Str2); + + Ptr = Str; + LastSlash = Str; + while (*Ptr != 0) { + if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') { + // + // Convert "\Name\..\" to "\" + // DO NOT convert the .. if it is at the end of the string. This will + // break the .. behavior in changing directories. + // + + // + // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpyS (TmpStr, MaxLen, Ptr + 3); + StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') { + // + // Convert a "\.\" to a "\" + // + + // + // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings + // that overlap. + // + StrCpyS (TmpStr, MaxLen, Ptr + 2); + StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr); + Ptr = LastSlash; + } else if (*Ptr == '\\') { + LastSlash = Ptr; + } + + Ptr++; + } + + FreePool (TmpStr); + + return Str; +} + +/** + This function build the FsOptionMenu list which records all + available file system in the system. They includes all instances + of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM. + + + @retval EFI_SUCCESS Success find the file system + @retval EFI_OUT_OF_RESOURCES Can not create menu entry + +**/ +EFI_STATUS +LibFindFileSystem ( + VOID + ) +{ + UINTN NoSimpleFsHandles; + UINTN NoLoadFileHandles; + EFI_HANDLE *SimpleFsHandle; + EFI_HANDLE *LoadFileHandle; + UINT16 *VolumeLabel; + UINTN Index; + EFI_STATUS Status; + MENU_ENTRY *MenuEntry; + FILE_CONTEXT *FileContext; + UINTN OptionNumber; + EFI_FILE_SYSTEM_VOLUME_LABEL *Info; + + NoSimpleFsHandles = 0; + NoLoadFileHandles = 0; + OptionNumber = 0; + + // + // Locate Handles that support Simple File System protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiSimpleFileSystemProtocolGuid, + NULL, + &NoSimpleFsHandles, + &SimpleFsHandle + ); + if (!EFI_ERROR (Status)) { + // + // Find all the instances of the File System prototocol + // + for (Index = 0; Index < NoSimpleFsHandles; Index++) { + // + // Allocate pool for this load option + // + MenuEntry = LibCreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (SimpleFsHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->DeviceHandle = SimpleFsHandle[Index]; + FileContext->FileHandle = LibOpenRoot (FileContext->DeviceHandle); + if (FileContext->FileHandle == NULL) { + LibDestroyMenuEntry (MenuEntry); + continue; + } + + MenuEntry->HelpString = LibDevicePathToStr (DevicePathFromHandle (FileContext->DeviceHandle)); + FileContext->FileName = LibStrDuplicate (L"\\"); + FileContext->DevicePath = FileDevicePath (FileContext->DeviceHandle, FileContext->FileName); + FileContext->IsDir = TRUE; + FileContext->IsRoot = TRUE; + + // + // Get current file system's Volume Label + // + Info = (EFI_FILE_SYSTEM_VOLUME_LABEL *) LibFileInfo (FileContext->FileHandle, &gEfiFileSystemVolumeLabelInfoIdGuid); + if (Info == NULL) { + VolumeLabel = L"NO FILE SYSTEM INFO"; + } else { + if (Info->VolumeLabel == NULL) { + VolumeLabel = L"NULL VOLUME LABEL"; + } else { + VolumeLabel = Info->VolumeLabel; + if (*VolumeLabel == 0x0000) { + VolumeLabel = L"NO VOLUME LABEL"; + } + } + } + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"%s, [%s]", + VolumeLabel, + MenuEntry->HelpString + ); + MenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + MenuEntry->DisplayString, + NULL + ); + FreePool (Info); + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); + } + } + + if (NoSimpleFsHandles != 0) { + FreePool (SimpleFsHandle); + } + + // + // Searching for handles that support Load File protocol + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadFileProtocolGuid, + NULL, + &NoLoadFileHandles, + &LoadFileHandle + ); + + if (!EFI_ERROR (Status)) { + for (Index = 0; Index < NoLoadFileHandles; Index++) { + MenuEntry = LibCreateMenuEntry (); + if (NULL == MenuEntry) { + FreePool (LoadFileHandle); + return EFI_OUT_OF_RESOURCES; + } + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + FileContext->DeviceHandle = LoadFileHandle[Index]; + FileContext->IsRoot = TRUE; + + FileContext->DevicePath = DevicePathFromHandle (FileContext->DeviceHandle); + FileContext->FileName = LibDevicePathToStr (FileContext->DevicePath); + + MenuEntry->HelpString = LibDevicePathToStr (FileContext->DevicePath); + MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR); + ASSERT (MenuEntry->DisplayString != NULL); + UnicodeSPrint ( + MenuEntry->DisplayString, + MAX_CHAR, + L"Load File [%s]", + MenuEntry->HelpString + ); + MenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + MenuEntry->DisplayString, + NULL + ); + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &MenuEntry->Link); + } + } + + if (NoLoadFileHandles != 0) { + FreePool (LoadFileHandle); + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input menu info. + + @param MenuEntry Input Menu info. + @param RetFileHandle Return the file handle for the input device path. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromMenu ( + IN MENU_ENTRY *MenuEntry, + OUT EFI_FILE_HANDLE *RetFileHandle + ) +{ + EFI_FILE_HANDLE Dir; + EFI_FILE_HANDLE NewDir; + FILE_CONTEXT *FileContext; + EFI_STATUS Status; + + FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext; + Dir = FileContext->FileHandle; + + // + // Open current directory to get files from it + // + Status = Dir->Open ( + Dir, + &NewDir, + FileContext->FileName, + EFI_FILE_READ_ONLY, + 0 + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!FileContext->IsRoot) { + Dir->Close (Dir); + } + + *RetFileHandle = NewDir; + + return EFI_SUCCESS; +} + +/** + Find the file handle from the input device path info. + + @param RootDirectory Device path info. + @param RetFileHandle Return the file handle for the input device path. + @param ParentFileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCESS Find the file handle success. + @retval Other Find the file handle failure. +**/ +EFI_STATUS +LibGetFileHandleFromDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + OUT EFI_FILE_HANDLE *RetFileHandle, + OUT UINT16 **ParentFileName, + OUT EFI_HANDLE *DeviceHandle + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathNode; + EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode; + EFI_STATUS Status; + EFI_HANDLE Handle; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume; + EFI_FILE_HANDLE FileHandle; + EFI_FILE_HANDLE LastHandle; + CHAR16 *TempPath; + + *ParentFileName = NULL; + + // + // Attempt to access the file via a file system interface + // + DevicePathNode = RootDirectory; + Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &DevicePathNode, &Handle); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = gBS->HandleProtocol (Handle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&Volume); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Open the Volume to get the File System handle + // + Status = Volume->OpenVolume (Volume, &FileHandle); + if (EFI_ERROR (Status)) { + return Status; + } + + *DeviceHandle = Handle; + + if (IsDevicePathEnd(DevicePathNode)) { + *ParentFileName = AllocateCopyPool (StrSize (L"\\"), L"\\"); + *RetFileHandle = FileHandle; + return EFI_SUCCESS; + } + + // + // Duplicate the device path to avoid the access to unaligned device path node. + // Because the device path consists of one or more FILE PATH MEDIA DEVICE PATH + // nodes, It assures the fields in device path nodes are 2 byte aligned. + // + TempDevicePathNode = DuplicateDevicePath (DevicePathNode); + if (TempDevicePathNode == NULL) { + + // + // Setting Status to an EFI_ERROR value will cause the rest of + // the file system support below to be skipped. + // + Status = EFI_OUT_OF_RESOURCES; + } + + // + // Parse each MEDIA_FILEPATH_DP node. There may be more than one, since the + // directory information and filename can be seperate. The goal is to inch + // our way down each device path node and close the previous node + // + DevicePathNode = TempDevicePathNode; + while (!EFI_ERROR (Status) && !IsDevicePathEnd (DevicePathNode)) { + if (DevicePathType (DevicePathNode) != MEDIA_DEVICE_PATH || + DevicePathSubType (DevicePathNode) != MEDIA_FILEPATH_DP) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + LastHandle = FileHandle; + FileHandle = NULL; + + Status = LastHandle->Open ( + LastHandle, + &FileHandle, + ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName, + EFI_FILE_MODE_READ, + 0 + ); + if (*ParentFileName == NULL) { + *ParentFileName = AllocateCopyPool (StrSize (((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName), ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + } else { + TempPath = LibAppendFileName (*ParentFileName, ((FILEPATH_DEVICE_PATH *) DevicePathNode)->PathName); + FreePool (*ParentFileName); + *ParentFileName = TempPath; + } + + // + // Close the previous node + // + LastHandle->Close (LastHandle); + + DevicePathNode = NextDevicePathNode (DevicePathNode); + } + + if (EFI_ERROR (Status)) { + goto Done; + } + + *RetFileHandle = FileHandle; + + Status = EFI_SUCCESS; + +Done: + if (TempDevicePathNode != NULL) { + FreePool (TempDevicePathNode); + } + + if ((FileHandle != NULL) && (EFI_ERROR (Status))) { + FileHandle->Close (FileHandle); + } + + return Status; +} + +/** + Find files under current directory. + + All files and sub-directories in current directory + will be stored in DirectoryMenu for future use. + + @param FileHandle Parent file handle. + @param FileName Parent file name. + @param DeviceHandle Driver handle for this partition. + + @retval EFI_SUCCESS Get files from current dir successfully. + @return Other value if can't get files from current dir. + +**/ +EFI_STATUS +LibFindFiles ( + IN EFI_FILE_HANDLE FileHandle, + IN UINT16 *FileName, + IN EFI_HANDLE DeviceHandle + ) +{ + EFI_FILE_INFO *DirInfo; + UINTN BufferSize; + UINTN DirBufferSize; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + UINTN Pass; + EFI_STATUS Status; + UINTN OptionNumber; + + OptionNumber = 0; + + DirBufferSize = sizeof (EFI_FILE_INFO) + 1024; + DirInfo = AllocateZeroPool (DirBufferSize); + if (DirInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all files in current directory + // Pass 1 to get Directories + // Pass 2 to get files that are EFI images + // + for (Pass = 1; Pass <= 2; Pass++) { + FileHandle->SetPosition (FileHandle, 0); + for (;;) { + BufferSize = DirBufferSize; + Status = FileHandle->Read (FileHandle, &BufferSize, DirInfo); + if (EFI_ERROR (Status) || BufferSize == 0) { + break; + } + + if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) || + ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1) + ) { + // + // Pass 1 is for Directories + // Pass 2 is for file names + // + continue; + } + + if (!((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 || LibIsSupportedFileType (DirInfo->FileName))) { + // + // Slip file unless it is a directory entry or a .EFI file + // + continue; + } + + NewMenuEntry = LibCreateMenuEntry (); + if (NULL == NewMenuEntry) { + return EFI_OUT_OF_RESOURCES; + } + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + NewFileContext->DeviceHandle = DeviceHandle; + NewFileContext->FileName = LibAppendFileName (FileName, DirInfo->FileName); + NewFileContext->FileHandle = FileHandle; + NewFileContext->DevicePath = FileDevicePath (NewFileContext->DeviceHandle, NewFileContext->FileName); + NewMenuEntry->HelpString = NULL; + NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY); + + if (NewFileContext->IsDir) { + BufferSize = StrLen (DirInfo->FileName) * 2 + 6; + NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize); + UnicodeSPrint ( + NewMenuEntry->DisplayString, + BufferSize, + L"<%s>", + DirInfo->FileName + ); + } else { + NewMenuEntry->DisplayString = LibStrDuplicate (DirInfo->FileName); + } + + NewMenuEntry->DisplayStringToken = HiiSetString ( + gFileExplorerPrivate.FeHiiHandle, + 0, + NewMenuEntry->DisplayString, + NULL + ); + + NewFileContext->IsRoot = FALSE; + + OptionNumber++; + InsertTailList (&gFileExplorerPrivate.FsOptionMenu->Head, &NewMenuEntry->Link); + } + } + + gFileExplorerPrivate.FsOptionMenu->MenuNumber = OptionNumber; + + FreePool (DirInfo); + + return EFI_SUCCESS; +} + +/** + Refresh the global UpdateData structure. + +**/ +VOID +LibRefreshUpdateData ( + VOID + ) +{ + // + // Free current updated date + // + if (mLibStartOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibStartOpCodeHandle); + } + if (mLibEndOpCodeHandle != NULL) { + HiiFreeOpCodeHandle (mLibEndOpCodeHandle); + } + + // + // Create new OpCode Handle + // + mLibStartOpCodeHandle = HiiAllocateOpCodeHandle (); + mLibEndOpCodeHandle = HiiAllocateOpCodeHandle (); + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibStartOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibStartLabel->Number = FORM_FILE_EXPLORER_ID; + + // + // Create Hii Extend Label OpCode as the start opcode + // + mLibEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( + mLibEndOpCodeHandle, + &gEfiIfrTianoGuid, + NULL, + sizeof (EFI_IFR_GUID_LABEL) + ); + mLibEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; + + mLibEndLabel->Number = LABEL_END; +} + +/** + + Update the File Explore page. + +**/ +VOID +LibUpdateFileExplorePage ( + VOID + ) +{ + UINTN Index; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + MENU_OPTION *MenuOption; + + NewMenuEntry = NULL; + NewFileContext = NULL; + + LibRefreshUpdateData (); + MenuOption = gFileExplorerPrivate.FsOptionMenu; + + for (Index = 0; Index < MenuOption->MenuNumber; Index++) { + NewMenuEntry = LibGetMenuEntry (MenuOption, Index); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (!NewFileContext->IsDir) { + // + // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile. + // + HiiCreateActionOpCode ( + mLibStartOpCodeHandle, + (UINT16) (FILE_OPTION_OFFSET + Index), + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + 0 + ); + } else { + // + // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState. + // + HiiCreateGotoOpCode ( + mLibStartOpCodeHandle, + FORM_FILE_EXPLORER_ID, + NewMenuEntry->DisplayStringToken, + STRING_TOKEN (STR_NULL_STRING), + EFI_IFR_FLAG_CALLBACK, + (UINT16) (FILE_OPTION_OFFSET + Index) + ); + } + } + + HiiUpdateForm ( + gFileExplorerPrivate.FeHiiHandle, + &FileExplorerGuid, + FORM_FILE_EXPLORER_ID, + mLibStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID + mLibEndOpCodeHandle // LABEL_END + ); +} + +/** + Update the file explower page with the refershed file system. + + @param KeyValue Key value to identify the type of data to expect. + + @retval EFI_SUCCESS Update the file explorer form success. + @retval other errors Error occur when parse one directory. + +**/ +EFI_STATUS +LibUpdateFileExplorer ( + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + EFI_STATUS Status; + EFI_FILE_HANDLE FileHandle; + + Status = EFI_SUCCESS; + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (NewFileContext->IsDir) { + RemoveEntryList (&NewMenuEntry->Link); + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + LibGetFileHandleFromMenu (NewMenuEntry, &FileHandle); + Status = LibFindFiles (FileHandle, NewFileContext->FileName, NewFileContext->DeviceHandle); + if (!EFI_ERROR (Status)) { + LibUpdateFileExplorePage (); + } else { + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + } + LibDestroyMenuEntry (NewMenuEntry); + } + + return Status; +} + +/** + Get the device path info saved in the menu structure. + + @param KeyValue Key value to identify the type of data to expect. + +**/ +VOID +LibGetDevicePath ( + IN UINT16 KeyValue + ) +{ + UINT16 FileOptionMask; + MENU_ENTRY *NewMenuEntry; + FILE_CONTEXT *NewFileContext; + + FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue); + + NewMenuEntry = LibGetMenuEntry (gFileExplorerPrivate.FsOptionMenu, FileOptionMask); + + NewFileContext = (FILE_CONTEXT *) NewMenuEntry->VariableContext; + + if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + gFileExplorerPrivate.RetDevicePath = DuplicateDevicePath (NewFileContext->DevicePath); +} + +/** + Choose a file in the specified directory. + + If user input NULL for the RootDirectory, will choose file in the system. + + If user input *File != NULL, function will return the allocate device path + info for the choosed file, caller has to free the memory after use it. + + @param RootDirectory Pointer to the root directory. + @param FileType The file type need to choose. + @param ChooseHandler Function pointer to the extra task need to do + after choose one file. + @param File Return the device path for the last time chosed file. + + @retval EFI_SUCESS Choose file success. + @retval EFI_INVALID_PARAMETER Both ChooseHandler and return device path are NULL + One of them must not NULL. + @retval Other errors Choose file failed. +**/ +EFI_STATUS +EFIAPI +ChooseFile ( + IN EFI_DEVICE_PATH_PROTOCOL *RootDirectory, + IN CHAR16 *FileType, OPTIONAL + IN CHOOSE_HANDLER ChooseHandler, OPTIONAL + OUT EFI_DEVICE_PATH_PROTOCOL **File OPTIONAL + ) +{ + EFI_FILE_HANDLE FileHandle; + EFI_STATUS Status; + UINT16 *FileName; + EFI_HANDLE DeviceHandle; + + if ((ChooseHandler == NULL) && (File == NULL)) { + return EFI_INVALID_PARAMETER; + } + + FileName = NULL; + + gFileExplorerPrivate.RetDevicePath = NULL; + gFileExplorerPrivate.ChooseHandler = ChooseHandler; + if (FileType != NULL) { + gFileExplorerPrivate.FileType = AllocateCopyPool (StrSize (FileType), FileType); + LibToLowerString(gFileExplorerPrivate.FileType); + } else { + gFileExplorerPrivate.FileType = NULL; + } + + if (RootDirectory == NULL) { + Status = LibFindFileSystem(); + } else { + Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = LibFindFiles (FileHandle, FileName, DeviceHandle); + } + if (EFI_ERROR (Status)) { + goto Done; + } + + LibUpdateFileExplorePage(); + + gFileExplorerPrivate.FormBrowser2->SendForm ( + gFileExplorerPrivate.FormBrowser2, + &gFileExplorerPrivate.FeHiiHandle, + 1, + &FileExplorerGuid, + 0, + NULL, + NULL + ); + +Done: + if ((Status == EFI_SUCCESS) && (File != NULL)) { + *File = gFileExplorerPrivate.RetDevicePath; + } else if (gFileExplorerPrivate.RetDevicePath != NULL) { + FreePool (gFileExplorerPrivate.RetDevicePath); + } + + if (gFileExplorerPrivate.FileType != NULL) { + FreePool (gFileExplorerPrivate.FileType); + } + + LibFreeMenu (gFileExplorerPrivate.FsOptionMenu); + + if (FileName != NULL) { + FreePool (FileName); + } + + return Status; +} + +/** + + Install Boot Manager Menu driver. + + @param ImageHandle The image handle. + @param SystemTable The system table. + + @retval EFI_SUCEESS Install File explorer library success. + +**/ +EFI_STATUS +EFIAPI +FileExplorerLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath); + ASSERT (gHiiVendorDevicePath != NULL); + CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid); + + // + // Install Device Path Protocol and Config Access protocol to driver handle + // + Status = gBS->InstallMultipleProtocolInterfaces ( + &gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + 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); + + 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); + + Status = gBS->UninstallMultipleProtocolInterfaces ( + gFileExplorerPrivate.FeDriverHandle, + &gEfiDevicePathProtocolGuid, + gHiiVendorDevicePath, + &gEfiHiiConfigAccessProtocolGuid, + &gFileExplorerPrivate.FeConfigAccess, + NULL + ); + ASSERT_EFI_ERROR (Status); + + HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle); + + FreePool (gHiiVendorDevicePath); + + return EFI_SUCCESS; +} + diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h index 4c27ea1d9d..fab20523ad 100644 --- a/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorer.h @@ -1,239 +1,239 @@ -/** @file - File explorer lib. - -Copyright (c) 2015, Intel Corporation. All rights reserved.
-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 -#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; - -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) - -#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 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 +/** @file + File explorer lib. + +Copyright (c) 2015, Intel Corporation. All rights reserved.
+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 +#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; + +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) + +#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 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/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf index b587bf5924..89c75f9416 100644 --- a/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf @@ -1,59 +1,59 @@ -## @file -# library defines a set of interfaces for how to do file explorer. -# -# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
-# 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. -# -## -[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 - HiiLib - -[Guids] - gEfiFileSystemVolumeLabelInfoIdGuid ## CONSUMES ## GUID (Indicate the information type is volume) - gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode) - -[Protocols] - gEfiSimpleFileSystemProtocolGuid ## CONSUMES - gEfiLoadFileProtocolGuid ## CONSUMES - gEfiHiiConfigAccessProtocolGuid ## CONSUMES - gEfiFormBrowser2ProtocolGuid ## CONSUMES +## @file +# library defines a set of interfaces for how to do file explorer. +# +# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.
+# 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. +# +## +[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 + HiiLib + +[Guids] + gEfiFileSystemVolumeLabelInfoIdGuid ## CONSUMES ## GUID (Indicate the information type is volume) + gEfiIfrTianoGuid ## CONSUMES ## GUID (Extended IFR Guid Opcode) + +[Protocols] + gEfiSimpleFileSystemProtocolGuid ## CONSUMES + gEfiLoadFileProtocolGuid ## CONSUMES + gEfiHiiConfigAccessProtocolGuid ## CONSUMES + gEfiFormBrowser2ProtocolGuid ## CONSUMES gEfiDevicePathToTextProtocolGuid ## CONSUMES \ No newline at end of file diff --git a/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr index 89dd81ad08..ef7c99c24f 100644 --- a/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr +++ b/MdeModulePkg/Library/FileExplorerLib/FileExplorerVfr.vfr @@ -1,31 +1,31 @@ -///** @file -// -// File Explorer Formset -// -// Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
-// 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. -// -//**/ - -#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; - +///** @file +// +// File Explorer Formset +// +// Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+// 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. +// +//**/ + +#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 index 6c23c6c5e4..011ae228c9 100644 --- a/MdeModulePkg/Library/FileExplorerLib/FormGuid.h +++ b/MdeModulePkg/Library/FileExplorerLib/FormGuid.h @@ -1,29 +1,29 @@ -/** @file -Formset guids, form id and VarStore data structure for File explorer library. - -Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
-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_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 - +/** @file +Formset guids, form id and VarStore data structure for File explorer library. + +Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.
+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_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 +