Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Dandan Bi <dandan.bi@intel.com> Reviewed-by: Eric Dong <eric.dong@intel.com>
		
			
				
	
	
		
			1519 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1519 lines
		
	
	
		
			42 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
File explorer related functions.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
 | 
						|
This program and the accompanying materials are licensed and made available under
 | 
						|
the terms and conditions of the BSD License that accompanies this distribution.
 | 
						|
The full text of the license may be found at
 | 
						|
http://opensource.org/licenses/bsd-license.php.
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
#include "FileExplorer.h"
 | 
						|
 | 
						|
EFI_GUID FileExplorerGuid       = EFI_FILE_EXPLORE_FORMSET_GUID;
 | 
						|
 | 
						|
///
 | 
						|
/// File system selection menu
 | 
						|
///
 | 
						|
MENU_OPTION      mFsOptionMenu = {
 | 
						|
  MENU_OPTION_SIGNATURE,
 | 
						|
  {NULL},
 | 
						|
  0,
 | 
						|
  FALSE
 | 
						|
};
 | 
						|
 | 
						|
FILE_EXPLORER_CALLBACK_DATA  gFileExplorerPrivate = {
 | 
						|
  FILE_EXPLORER_CALLBACK_DATA_SIGNATURE,
 | 
						|
  NULL,
 | 
						|
  NULL,
 | 
						|
  {
 | 
						|
    LibExtractConfig,
 | 
						|
    LibRouteConfig,
 | 
						|
    LibCallback
 | 
						|
  },
 | 
						|
  NULL,
 | 
						|
  &mFsOptionMenu,
 | 
						|
  0
 | 
						|
};
 | 
						|
 | 
						|
HII_VENDOR_DEVICE_PATH  *gHiiVendorDevicePath;
 | 
						|
 | 
						|
HII_VENDOR_DEVICE_PATH  FeHiiVendorDevicePath = {
 | 
						|
  {
 | 
						|
    {
 | 
						|
      HARDWARE_DEVICE_PATH,
 | 
						|
      HW_VENDOR_DP,
 | 
						|
      {
 | 
						|
        (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
 | 
						|
        (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
 | 
						|
      }
 | 
						|
    },
 | 
						|
    //
 | 
						|
    // Will be replace with gEfiCallerIdGuid in code.
 | 
						|
    //
 | 
						|
    { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }
 | 
						|
  },
 | 
						|
  {
 | 
						|
    END_DEVICE_PATH_TYPE,
 | 
						|
    END_ENTIRE_DEVICE_PATH_SUBTYPE,
 | 
						|
    { 
 | 
						|
      (UINT8) (END_DEVICE_PATH_LENGTH),
 | 
						|
      (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
 | 
						|
    }
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
VOID                *mLibStartOpCodeHandle = NULL;
 | 
						|
VOID                *mLibEndOpCodeHandle = NULL;
 | 
						|
EFI_IFR_GUID_LABEL  *mLibStartLabel = NULL;
 | 
						|
EFI_IFR_GUID_LABEL  *mLibEndLabel = NULL;
 | 
						|
 | 
						|
/**
 | 
						|
  This function allows a caller to extract the current configuration for one
 | 
						|
  or more named elements from the target driver.
 | 
						|
 | 
						|
 | 
						|
  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | 
						|
  @param Request         A null-terminated Unicode string in <ConfigRequest> format.
 | 
						|
  @param Progress        On return, points to a character in the Request string.
 | 
						|
                         Points to the string's null terminator if request was successful.
 | 
						|
                         Points to the most recent '&' before the first failing name/value
 | 
						|
                         pair (or the beginning of the string if the failure is in the
 | 
						|
                         first name/value pair) if the request was not successful.
 | 
						|
  @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
 | 
						|
                         has all values filled in for the names in the Request string.
 | 
						|
                         String to be allocated by the called function.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
 | 
						|
  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LibExtractConfig (
 | 
						|
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | 
						|
  IN  CONST EFI_STRING                       Request,
 | 
						|
  OUT EFI_STRING                             *Progress,
 | 
						|
  OUT EFI_STRING                             *Results
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (Progress == NULL || Results == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Progress = Request;
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function processes the results of changes in configuration.
 | 
						|
 | 
						|
 | 
						|
  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | 
						|
  @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
 | 
						|
  @param Progress        A pointer to a string filled in with the offset of the most
 | 
						|
                         recent '&' before the first failing name/value pair (or the
 | 
						|
                         beginning of the string if the failure is in the first
 | 
						|
                         name/value pair) or the terminating NULL if all was successful.
 | 
						|
 | 
						|
  @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
 | 
						|
  @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LibRouteConfig (
 | 
						|
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | 
						|
  IN  CONST EFI_STRING                       Configuration,
 | 
						|
  OUT EFI_STRING                             *Progress
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (Configuration == NULL || Progress == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Progress = Configuration;
 | 
						|
  return EFI_NOT_FOUND;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function processes the results of changes in configuration.
 | 
						|
  When user select a interactive opcode, this callback will be triggered.
 | 
						|
  Based on the Question(QuestionId) that triggers the callback, the corresponding
 | 
						|
  actions is performed. It handles:
 | 
						|
 | 
						|
  1) Process the axtra action or exit file explorer when user select one file .
 | 
						|
  2) update of file content if a dir is selected.
 | 
						|
 | 
						|
  @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
 | 
						|
  @param Action          Specifies the type of action taken by the browser.
 | 
						|
  @param QuestionId      A unique value which is sent to the original exporting driver
 | 
						|
                         so that it can identify the type of data to expect.
 | 
						|
  @param Type            The type of value for the question.
 | 
						|
  @param Value           A pointer to the data being sent to the original exporting driver.
 | 
						|
  @param ActionRequest   On return, points to the action requested by the callback function.
 | 
						|
 | 
						|
  @retval  EFI_SUCCESS           The callback successfully handled the action.
 | 
						|
  @retval  other error           Error occur when parse one directory.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
LibCallback (
 | 
						|
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
 | 
						|
  IN  EFI_BROWSER_ACTION                     Action,
 | 
						|
  IN  EFI_QUESTION_ID                        QuestionId,
 | 
						|
  IN  UINT8                                  Type,
 | 
						|
  IN  EFI_IFR_TYPE_VALUE                     *Value,
 | 
						|
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS    Status;
 | 
						|
  BOOLEAN       NeedExit;
 | 
						|
 | 
						|
  NeedExit = TRUE;
 | 
						|
  
 | 
						|
  if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
 | 
						|
    //
 | 
						|
    // Do nothing for other UEFI Action. Only do call back when data is changed.
 | 
						|
    //
 | 
						|
    return EFI_UNSUPPORTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Action == EFI_BROWSER_ACTION_CHANGED) {
 | 
						|
    if ((Value == NULL) || (ActionRequest == NULL)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (QuestionId >= FILE_OPTION_OFFSET) {
 | 
						|
      LibGetDevicePath(QuestionId);
 | 
						|
 | 
						|
      //
 | 
						|
      // Process the extra action.
 | 
						|
      //
 | 
						|
      if (gFileExplorerPrivate.ChooseHandler != NULL) {
 | 
						|
        NeedExit = gFileExplorerPrivate.ChooseHandler (gFileExplorerPrivate.RetDevicePath);
 | 
						|
      }
 | 
						|
 | 
						|
      if (NeedExit) {
 | 
						|
        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
 | 
						|
    if (Value == NULL) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
    
 | 
						|
    if (QuestionId >= FILE_OPTION_OFFSET) {
 | 
						|
      Status = LibUpdateFileExplorer (QuestionId);
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        return Status;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Create a menu entry by given menu type.
 | 
						|
 | 
						|
  @retval NULL           If failed to create the menu.
 | 
						|
  @return the new menu entry.
 | 
						|
 | 
						|
**/
 | 
						|
MENU_ENTRY *
 | 
						|
LibCreateMenuEntry (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  MENU_ENTRY *MenuEntry;
 | 
						|
 | 
						|
  //
 | 
						|
  // Create new menu entry
 | 
						|
  //
 | 
						|
  MenuEntry = AllocateZeroPool (sizeof (MENU_ENTRY));
 | 
						|
  if (MenuEntry == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  MenuEntry->VariableContext = AllocateZeroPool (sizeof (FILE_CONTEXT));
 | 
						|
  if (MenuEntry->VariableContext == NULL) {
 | 
						|
    FreePool (MenuEntry);
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  MenuEntry->Signature        = MENU_ENTRY_SIGNATURE;
 | 
						|
  return MenuEntry;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Get the Menu Entry from the list in Menu Entry List.
 | 
						|
 | 
						|
  If MenuNumber is great or equal to the number of Menu
 | 
						|
  Entry in the list, then ASSERT.
 | 
						|
 | 
						|
  @param MenuOption      The Menu Entry List to read the menu entry.
 | 
						|
  @param MenuNumber      The index of Menu Entry.
 | 
						|
 | 
						|
  @return The Menu Entry.
 | 
						|
 | 
						|
**/
 | 
						|
MENU_ENTRY *
 | 
						|
LibGetMenuEntry (
 | 
						|
  MENU_OPTION         *MenuOption,
 | 
						|
  UINTN               MenuNumber
 | 
						|
  )
 | 
						|
{
 | 
						|
  MENU_ENTRY      *NewMenuEntry;
 | 
						|
  UINTN           Index;
 | 
						|
  LIST_ENTRY      *List;
 | 
						|
 | 
						|
  ASSERT (MenuNumber < MenuOption->MenuNumber);
 | 
						|
 | 
						|
  List = MenuOption->Head.ForwardLink;
 | 
						|
  for (Index = 0; Index < MenuNumber; Index++) {
 | 
						|
    List = List->ForwardLink;
 | 
						|
  }
 | 
						|
 | 
						|
  NewMenuEntry = CR (List, MENU_ENTRY, Link, MENU_ENTRY_SIGNATURE);
 | 
						|
 | 
						|
  return NewMenuEntry;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Free up all resource allocated for a BM_MENU_ENTRY.
 | 
						|
 | 
						|
  @param MenuEntry   A pointer to BM_MENU_ENTRY.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
LibDestroyMenuEntry (
 | 
						|
  MENU_ENTRY         *MenuEntry
 | 
						|
  )
 | 
						|
{
 | 
						|
  FILE_CONTEXT           *FileContext;
 | 
						|
 | 
						|
  FileContext = (FILE_CONTEXT *) MenuEntry->VariableContext;
 | 
						|
 | 
						|
  if (!FileContext->IsRoot) {
 | 
						|
    if (FileContext->DevicePath != NULL) {
 | 
						|
      FreePool (FileContext->DevicePath);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    if (FileContext->FileHandle != NULL) {
 | 
						|
      FileContext->FileHandle->Close (FileContext->FileHandle);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (FileContext->FileName != NULL) {
 | 
						|
    FreePool (FileContext->FileName);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (FileContext);
 | 
						|
 | 
						|
  if (MenuEntry->DisplayString != NULL) {
 | 
						|
    FreePool (MenuEntry->DisplayString);
 | 
						|
  }
 | 
						|
  if (MenuEntry->HelpString != NULL) {
 | 
						|
    FreePool (MenuEntry->HelpString);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (MenuEntry);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Free resources allocated in Allocate Rountine.
 | 
						|
 | 
						|
  @param FreeMenu        Menu to be freed
 | 
						|
**/
 | 
						|
VOID
 | 
						|
LibFreeMenu (
 | 
						|
  MENU_OPTION        *FreeMenu
 | 
						|
  )
 | 
						|
{
 | 
						|
  MENU_ENTRY *MenuEntry;
 | 
						|
  while (!IsListEmpty (&FreeMenu->Head)) {
 | 
						|
    MenuEntry = CR (
 | 
						|
                  FreeMenu->Head.ForwardLink,
 | 
						|
                  MENU_ENTRY,
 | 
						|
                  Link,
 | 
						|
                  MENU_ENTRY_SIGNATURE
 | 
						|
                  );
 | 
						|
    RemoveEntryList (&MenuEntry->Link);
 | 
						|
    LibDestroyMenuEntry (MenuEntry);
 | 
						|
  }
 | 
						|
  FreeMenu->MenuNumber = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Function opens and returns a file handle to the root directory of a volume.
 | 
						|
 | 
						|
  @param DeviceHandle    A handle for a device
 | 
						|
 | 
						|
  @return A valid file handle or NULL is returned
 | 
						|
 | 
						|
**/
 | 
						|
EFI_FILE_HANDLE
 | 
						|
LibOpenRoot (
 | 
						|
  IN EFI_HANDLE                   DeviceHandle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                      Status;
 | 
						|
  EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
 | 
						|
  EFI_FILE_HANDLE                 File;
 | 
						|
 | 
						|
  File = NULL;
 | 
						|
 | 
						|
  //
 | 
						|
  // File the file system interface to the device
 | 
						|
  //
 | 
						|
  Status = gBS->HandleProtocol (
 | 
						|
                  DeviceHandle,
 | 
						|
                  &gEfiSimpleFileSystemProtocolGuid,
 | 
						|
                  (VOID *) &Volume
 | 
						|
                  );
 | 
						|
 | 
						|
  //
 | 
						|
  // Open the root directory of the volume
 | 
						|
  //
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
    Status = Volume->OpenVolume (
 | 
						|
                      Volume,
 | 
						|
                      &File
 | 
						|
                      );
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Done
 | 
						|
  //
 | 
						|
  return EFI_ERROR (Status) ? NULL : File;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function converts an input device structure to a Unicode string.
 | 
						|
 | 
						|
  @param DevPath                  A pointer to the device path structure.
 | 
						|
 | 
						|
  @return A new allocated Unicode string that represents the device path.
 | 
						|
 | 
						|
**/
 | 
						|
CHAR16 *
 | 
						|
LibDevicePathToStr (
 | 
						|
  IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  CHAR16                           *ToText;
 | 
						|
  EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
 | 
						|
 | 
						|
  if (DevPath == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gBS->LocateProtocol (
 | 
						|
                  &gEfiDevicePathToTextProtocolGuid,
 | 
						|
                  NULL,
 | 
						|
                  (VOID **) &DevPathToText
 | 
						|
                  );
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
  ToText = DevPathToText->ConvertDevicePathToText (
 | 
						|
                            DevPath,
 | 
						|
                            FALSE,
 | 
						|
                            TRUE
 | 
						|
                            );
 | 
						|
  ASSERT (ToText != NULL);
 | 
						|
 | 
						|
  return ToText;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Duplicate a string.
 | 
						|
 | 
						|
  @param Src             The source.
 | 
						|
 | 
						|
  @return A new string which is duplicated copy of the source.
 | 
						|
  @retval NULL If there is not enough memory.
 | 
						|
 | 
						|
**/
 | 
						|
CHAR16 *
 | 
						|
LibStrDuplicate (
 | 
						|
  IN CHAR16   *Src
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16  *Dest;
 | 
						|
  UINTN   Size;
 | 
						|
 | 
						|
  Size  = StrSize (Src);
 | 
						|
  Dest  = AllocateZeroPool (Size);
 | 
						|
  ASSERT (Dest != NULL);
 | 
						|
  if (Dest != NULL) {
 | 
						|
    CopyMem (Dest, Src, Size);
 | 
						|
  }
 | 
						|
 | 
						|
  return Dest;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Function gets the file information from an open file descriptor, and stores it
 | 
						|
  in a buffer allocated from pool.
 | 
						|
 | 
						|
  @param FHand           File Handle.
 | 
						|
  @param InfoType        Info type need to get.
 | 
						|
 | 
						|
  @retval                A pointer to a buffer with file information or NULL is returned
 | 
						|
 | 
						|
**/
 | 
						|
VOID *
 | 
						|
LibFileInfo (
 | 
						|
  IN EFI_FILE_HANDLE      FHand,
 | 
						|
  IN EFI_GUID             *InfoType
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS    Status;
 | 
						|
  EFI_FILE_INFO *Buffer;
 | 
						|
  UINTN         BufferSize;
 | 
						|
 | 
						|
  Buffer      = NULL;
 | 
						|
  BufferSize  = 0;
 | 
						|
  
 | 
						|
  Status = FHand->GetInfo (
 | 
						|
                    FHand,
 | 
						|
                    InfoType,
 | 
						|
                    &BufferSize,
 | 
						|
                    Buffer
 | 
						|
                    );
 | 
						|
  if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
    Buffer = AllocatePool (BufferSize);
 | 
						|
    ASSERT (Buffer != NULL);
 | 
						|
  }
 | 
						|
 | 
						|
  Status = FHand->GetInfo (
 | 
						|
                    FHand,
 | 
						|
                    InfoType,
 | 
						|
                    &BufferSize,
 | 
						|
                    Buffer
 | 
						|
                    );
 | 
						|
 | 
						|
  return Buffer;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Get file type base on the file name.
 | 
						|
  Just cut the file name, from the ".". eg ".efi"
 | 
						|
 | 
						|
  @param FileName  File need to be checked.
 | 
						|
 | 
						|
  @retval the file type string.
 | 
						|
 | 
						|
**/
 | 
						|
CHAR16*
 | 
						|
LibGetTypeFromName (
 | 
						|
  IN CHAR16   *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN    Index;
 | 
						|
 | 
						|
  Index = StrLen (FileName) - 1;
 | 
						|
  while ((FileName[Index] != L'.') && (Index != 0)) {
 | 
						|
    Index--;
 | 
						|
  }
 | 
						|
 | 
						|
  return Index == 0 ? NULL : &FileName[Index];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Converts the unicode character of the string from uppercase to lowercase.
 | 
						|
  This is a internal function.
 | 
						|
 | 
						|
  @param ConfigString  String to be converted
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
LibToLowerString (
 | 
						|
  IN CHAR16  *String
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16      *TmpStr;
 | 
						|
 | 
						|
  for (TmpStr = String; *TmpStr != L'\0'; TmpStr++) {
 | 
						|
    if (*TmpStr >= L'A' && *TmpStr <= L'Z') {
 | 
						|
      *TmpStr = (CHAR16) (*TmpStr - L'A' + L'a');
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Check whether current FileName point to a valid
 | 
						|
  Efi Image File.
 | 
						|
 | 
						|
  @param FileName  File need to be checked.
 | 
						|
 | 
						|
  @retval TRUE  Is Efi Image
 | 
						|
  @retval FALSE Not a valid Efi Image
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
LibIsSupportedFileType (
 | 
						|
  IN UINT16  *FileName
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR16     *InputFileType;
 | 
						|
  CHAR16     *TmpStr;
 | 
						|
  BOOLEAN    IsSupported;
 | 
						|
 | 
						|
  if (gFileExplorerPrivate.FileType == NULL) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  InputFileType = LibGetTypeFromName (FileName);
 | 
						|
  //
 | 
						|
  // If the file not has *.* style, always return TRUE.
 | 
						|
  //
 | 
						|
  if (InputFileType == NULL) {
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  TmpStr = AllocateCopyPool (StrSize (InputFileType), InputFileType);
 | 
						|
  ASSERT(TmpStr != NULL);
 | 
						|
  LibToLowerString(TmpStr);
 | 
						|
 | 
						|
  IsSupported = (StrStr (gFileExplorerPrivate.FileType, TmpStr) == NULL ? FALSE : TRUE);
 | 
						|
 | 
						|
  FreePool (TmpStr);
 | 
						|
  return IsSupported;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Append file name to existing file name.
 | 
						|
 | 
						|
  @param Str1  The existing file name
 | 
						|
  @param Str2  The file name to be appended
 | 
						|
 | 
						|
  @return Allocate a new string to hold the appended result.
 | 
						|
          Caller is responsible to free the returned string.
 | 
						|
 | 
						|
**/
 | 
						|
CHAR16 *
 | 
						|
LibAppendFileName (
 | 
						|
  IN  CHAR16  *Str1,
 | 
						|
  IN  CHAR16  *Str2
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN   Size1;
 | 
						|
  UINTN   Size2;
 | 
						|
  UINTN   MaxLen;
 | 
						|
  CHAR16  *Str;
 | 
						|
  CHAR16  *TmpStr;
 | 
						|
  CHAR16  *Ptr;
 | 
						|
  CHAR16  *LastSlash;
 | 
						|
 | 
						|
  Size1 = StrSize (Str1);
 | 
						|
  Size2 = StrSize (Str2);
 | 
						|
  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);
 | 
						|
    ASSERT(gFileExplorerPrivate.FileType != NULL);
 | 
						|
    LibToLowerString(gFileExplorerPrivate.FileType);
 | 
						|
  } else {
 | 
						|
    gFileExplorerPrivate.FileType = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (RootDirectory == NULL) {
 | 
						|
    Status = LibFindFileSystem();
 | 
						|
  } else {
 | 
						|
    Status = LibGetFileHandleFromDevicePath(RootDirectory, &FileHandle, &FileName, &DeviceHandle);
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      goto Done;
 | 
						|
    }
 | 
						|
 | 
						|
    Status = LibFindFiles (FileHandle, FileName, DeviceHandle);
 | 
						|
  }
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto Done;
 | 
						|
  }
 | 
						|
 | 
						|
  LibUpdateFileExplorePage();
 | 
						|
 | 
						|
  gFileExplorerPrivate.FormBrowser2->SendForm (
 | 
						|
                         gFileExplorerPrivate.FormBrowser2,
 | 
						|
                         &gFileExplorerPrivate.FeHiiHandle,
 | 
						|
                         1,
 | 
						|
                         &FileExplorerGuid,
 | 
						|
                         0,
 | 
						|
                         NULL,
 | 
						|
                         NULL
 | 
						|
                         );
 | 
						|
 | 
						|
Done:
 | 
						|
  if ((Status == EFI_SUCCESS) && (File != NULL)) {
 | 
						|
    *File  = gFileExplorerPrivate.RetDevicePath;
 | 
						|
  } else if (gFileExplorerPrivate.RetDevicePath != NULL) {
 | 
						|
    FreePool (gFileExplorerPrivate.RetDevicePath);
 | 
						|
  }
 | 
						|
 | 
						|
  if (gFileExplorerPrivate.FileType != NULL) {
 | 
						|
    FreePool (gFileExplorerPrivate.FileType);
 | 
						|
  }
 | 
						|
 | 
						|
  LibFreeMenu (gFileExplorerPrivate.FsOptionMenu);
 | 
						|
 | 
						|
  if (FileName != NULL) {
 | 
						|
    FreePool (FileName);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 | 
						|
  Install Boot Manager Menu driver.
 | 
						|
 | 
						|
  @param ImageHandle     The image handle.
 | 
						|
  @param SystemTable     The system table.
 | 
						|
 | 
						|
  @retval  EFI_SUCEESS  Install File explorer library success.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileExplorerLibConstructor (
 | 
						|
  IN EFI_HANDLE                            ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE                      *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                     Status;
 | 
						|
 | 
						|
  gHiiVendorDevicePath = (HII_VENDOR_DEVICE_PATH*) DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)&FeHiiVendorDevicePath);
 | 
						|
  ASSERT (gHiiVendorDevicePath != NULL);
 | 
						|
  CopyGuid (&gHiiVendorDevicePath->VendorDevicePath.Guid, &gEfiCallerIdGuid);
 | 
						|
 | 
						|
  //
 | 
						|
  // Install Device Path Protocol and Config Access protocol to driver handle
 | 
						|
  //
 | 
						|
  Status = gBS->InstallMultipleProtocolInterfaces (
 | 
						|
                  &gFileExplorerPrivate.FeDriverHandle,
 | 
						|
                  &gEfiDevicePathProtocolGuid,
 | 
						|
                  gHiiVendorDevicePath,
 | 
						|
                  &gEfiHiiConfigAccessProtocolGuid,
 | 
						|
                  &gFileExplorerPrivate.FeConfigAccess,
 | 
						|
                  NULL
 | 
						|
                  );
 | 
						|
  if (Status == EFI_ALREADY_STARTED) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Post our File Explorer VFR binary to the HII database.
 | 
						|
  //
 | 
						|
  gFileExplorerPrivate.FeHiiHandle = HiiAddPackages (
 | 
						|
                                   &FileExplorerGuid,
 | 
						|
                                   gFileExplorerPrivate.FeDriverHandle,
 | 
						|
                                   FileExplorerVfrBin,
 | 
						|
                                   FileExplorerLibStrings,
 | 
						|
                                   NULL
 | 
						|
                                   );
 | 
						|
  ASSERT (gFileExplorerPrivate.FeHiiHandle != NULL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Locate Formbrowser2 protocol
 | 
						|
  //
 | 
						|
  Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFileExplorerPrivate.FormBrowser2);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
    
 | 
						|
  InitializeListHead (&gFileExplorerPrivate.FsOptionMenu->Head);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Unloads the application and its installed protocol.
 | 
						|
 | 
						|
  @param[in]  ImageHandle       Handle that identifies the image to be unloaded.
 | 
						|
  @param[in]  SystemTable       The system table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           The image has been unloaded.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
FileExplorerLibDestructor (
 | 
						|
  IN EFI_HANDLE                            ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE                      *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS    Status;
 | 
						|
 | 
						|
  ASSERT (gHiiVendorDevicePath != NULL);
 | 
						|
 | 
						|
  if (gFileExplorerPrivate.FeDriverHandle != NULL) {
 | 
						|
    Status = gBS->UninstallMultipleProtocolInterfaces (
 | 
						|
                    gFileExplorerPrivate.FeDriverHandle,
 | 
						|
                    &gEfiDevicePathProtocolGuid,
 | 
						|
                    gHiiVendorDevicePath,
 | 
						|
                    &gEfiHiiConfigAccessProtocolGuid,
 | 
						|
                    &gFileExplorerPrivate.FeConfigAccess,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
    ASSERT_EFI_ERROR (Status);
 | 
						|
    
 | 
						|
    HiiRemovePackages (gFileExplorerPrivate.FeHiiHandle);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (gHiiVendorDevicePath);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 |