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