]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/BaseShellLib/BaseShellLib.c
fixed to build under IPF.
[mirror_edk2.git] / ShellPkg / Library / BaseShellLib / BaseShellLib.c
index 205974d519168435479176b70e56c7bcfc301436..a0e2e492e11028a2d9ab912f67dc53a088924d3a 100644 (file)
@@ -20,21 +20,35 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 #include <Library/DebugLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/DevicePathLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/FileHandleLib.h>\r
 #include <Protocol/EfiShellEnvironment2.h>\r
 #include <Protocol/EfiShellInterface.h>\r
 #include <Protocol/EfiShell.h>\r
 #include <Protocol/EfiShellParameters.h>\r
 #include <Protocol/SimpleFileSystem.h>\r
 \r
+#include "BaseShellLib.h"\r
+\r
 #define MAX_FILE_NAME_LEN 522 // (20 * (6+5+2))+1) unicode characters from EFI FAT spec (doubled for bytes)\r
 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)\r
 \r
-EFI_SHELL_ENVIRONMENT2        *mEfiShellEnvironment2;\r
-EFI_SHELL_INTERFACE           *mEfiShellInterface;\r
-EFI_SHELL_PROTOCOL            *mEfiShellProtocol;\r
-EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;\r
-EFI_HANDLE                    mEfiShellEnvironment2Handle;\r
-EFI_LIST_ENTRY                *mOldStyleFileList;\r
+//\r
+// This is not static since it's extern in the .h file\r
+//\r
+SHELL_PARAM_ITEM EmptyParamList[] = {\r
+  {NULL, TypeMax}\r
+  };\r
+\r
+//\r
+// Static file globals for the shell library\r
+//\r
+STATIC EFI_SHELL_ENVIRONMENT2        *mEfiShellEnvironment2;\r
+STATIC EFI_SHELL_INTERFACE           *mEfiShellInterface;\r
+STATIC EFI_SHELL_PROTOCOL            *mEfiShellProtocol;\r
+STATIC EFI_SHELL_PARAMETERS_PROTOCOL *mEfiShellParametersProtocol;\r
+STATIC EFI_HANDLE                    mEfiShellEnvironment2Handle;\r
+STATIC FILE_HANDLE_FUNCTION_MAP      FileFunctionMap;\r
 \r
 /**\r
   helper function to find ShellEnvironment2 for constructor\r
@@ -112,36 +126,14 @@ ShellFindSE2 (
   return (Status);\r
 }\r
 \r
-/**\r
-  Constructor for the Shell library.\r
-\r
-  Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.\r
-\r
-  @param ImageHandle    the image handle of the process\r
-  @param SystemTable    the EFI System Table pointer\r
-\r
-  @retval EFI_SUCCESS   the initialization was complete sucessfully\r
-  @return others        an error ocurred during initialization\r
-**/\r
 EFI_STATUS\r
 EFIAPI\r
-ShellLibConstructor (\r
+ShellLibConstructorWorker (\r
   IN EFI_HANDLE        ImageHandle,\r
   IN EFI_SYSTEM_TABLE  *SystemTable\r
-  )\r
-{\r
+){\r
   EFI_STATUS Status;\r
 \r
-  ASSERT(SystemTable != NULL);\r
-  ASSERT(gBS != NULL);\r
-\r
-  mEfiShellEnvironment2       = NULL;\r
-  mEfiShellProtocol           = NULL;\r
-  mEfiShellParametersProtocol = NULL;\r
-  mEfiShellInterface          = NULL;\r
-  mEfiShellEnvironment2Handle = NULL;\r
-  mOldStyleFileList           = NULL;\r
-\r
   //\r
   // UEFI 2.0 shell interfaces (used preferentially)\r
   //\r
@@ -192,10 +184,69 @@ ShellLibConstructor (
   //\r
   if ((mEfiShellEnvironment2 != NULL && mEfiShellInterface          != NULL) || \r
       (mEfiShellProtocol     != NULL && mEfiShellParametersProtocol != NULL)    ) {\r
+    if (mEfiShellProtocol != NULL) {\r
+      FileFunctionMap.GetFileInfo     = mEfiShellProtocol->GetFileInfo;\r
+      FileFunctionMap.SetFileInfo     = mEfiShellProtocol->SetFileInfo;\r
+      FileFunctionMap.ReadFile        = mEfiShellProtocol->ReadFile;\r
+      FileFunctionMap.WriteFile       = mEfiShellProtocol->WriteFile;\r
+      FileFunctionMap.CloseFile       = mEfiShellProtocol->CloseFile;\r
+      FileFunctionMap.DeleteFile      = mEfiShellProtocol->DeleteFile;\r
+      FileFunctionMap.GetFilePosition = mEfiShellProtocol->GetFilePosition;\r
+      FileFunctionMap.SetFilePosition = mEfiShellProtocol->SetFilePosition;\r
+      FileFunctionMap.FlushFile       = mEfiShellProtocol->FlushFile;\r
+      FileFunctionMap.GetFileSize     = mEfiShellProtocol->GetFileSize;\r
+    } else {\r
+      FileFunctionMap.GetFileInfo     = FileHandleGetInfo;\r
+      FileFunctionMap.SetFileInfo     = FileHandleSetInfo;\r
+      FileFunctionMap.ReadFile        = FileHandleRead;\r
+      FileFunctionMap.WriteFile       = FileHandleWrite;\r
+      FileFunctionMap.CloseFile       = FileHandleClose;\r
+      FileFunctionMap.DeleteFile      = FileHandleDelete;\r
+      FileFunctionMap.GetFilePosition = FileHandleGetPosition;\r
+      FileFunctionMap.SetFilePosition = FileHandleSetPosition;\r
+      FileFunctionMap.FlushFile       = FileHandleFlush;\r
+      FileFunctionMap.GetFileSize     = FileHandleGetSize;\r
+    }\r
     return (EFI_SUCCESS);\r
   }\r
   return (EFI_NOT_FOUND);\r
 }\r
+/**\r
+  Constructor for the Shell library.\r
+\r
+  Initialize the library and determine if the underlying is a UEFI Shell 2.0 or an EFI shell.\r
+\r
+  @param ImageHandle    the image handle of the process\r
+  @param SystemTable    the EFI System Table pointer\r
+\r
+  @retval EFI_SUCCESS   the initialization was complete sucessfully\r
+  @return others        an error ocurred during initialization\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+\r
+\r
+  mEfiShellEnvironment2       = NULL;\r
+  mEfiShellProtocol           = NULL;\r
+  mEfiShellParametersProtocol = NULL;\r
+  mEfiShellInterface          = NULL;\r
+  mEfiShellEnvironment2Handle = NULL;\r
+\r
+  ///@todo make a worker constructor so initialize function works\r
+  //\r
+  // verify that auto initialize is not set false\r
+  // \r
+  if (PcdGetBool(PcdShellLibAutoInitialize) == 0) {\r
+    return (EFI_SUCCESS);\r
+  }\r
+  \r
+  return (ShellLibConstructorWorker(ImageHandle, SystemTable));\r
+}\r
 \r
 /**\r
   Destructory for the library.  free any resources.\r
@@ -212,27 +263,68 @@ ShellLibDestructor (
                        &gEfiShellEnvironment2Guid,\r
                        ImageHandle,\r
                        NULL);\r
+    mEfiShellEnvironment2 = NULL;\r
   }\r
   if (mEfiShellInterface != NULL) {\r
     gBS->CloseProtocol(ImageHandle,\r
                        &gEfiShellInterfaceGuid,\r
                        ImageHandle,\r
                        NULL);  \r
+    mEfiShellInterface = NULL;\r
   }\r
   if (mEfiShellProtocol != NULL) {\r
     gBS->CloseProtocol(ImageHandle,\r
                        &gEfiShellProtocolGuid,\r
                        ImageHandle,\r
-                       NULL);    \r
+                       NULL);  \r
+    mEfiShellProtocol = NULL;\r
   }\r
   if (mEfiShellParametersProtocol != NULL) {\r
     gBS->CloseProtocol(ImageHandle,\r
                        &gEfiShellParametersProtocolGuid,\r
                        ImageHandle,\r
                        NULL);    \r
+    mEfiShellParametersProtocol = NULL;\r
   }\r
+  mEfiShellEnvironment2Handle = NULL;\r
   return (EFI_SUCCESS);\r
 }\r
+\r
+/**\r
+  This function causes the shell library to initialize itself.  If the shell library\r
+  is already initialized it will de-initialize all the current protocol poitners and\r
+  re-populate them again.\r
+\r
+  When the library is used with PcdShellLibAutoInitialize set to true this function\r
+  will return EFI_SUCCESS and perform no actions.\r
+\r
+  This function is intended for internal access for shell commands only.\r
+\r
+  @retval EFI_SUCCESS   the initialization was complete sucessfully\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ShellInitialize (\r
+  ) {\r
+  //\r
+  // if auto initialize is not false then skip\r
+  //\r
+  if (PcdGetBool(PcdShellLibAutoInitialize) != 0) {\r
+    return (EFI_SUCCESS);\r
+  }\r
+\r
+  //\r
+  // deinit the current stuff\r
+  //\r
+  ASSERT_EFI_ERROR(ShellLibDestructor(gImageHandle, gST));\r
+\r
+  //\r
+  // init the new stuff\r
+  //\r
+  return (ShellLibConstructorWorker(gImageHandle, gST));\r
+}\r
+\r
 /**\r
   This function will retrieve the information about the file for the handle \r
   specified and store it in allocated pool memory.\r
@@ -253,47 +345,7 @@ ShellGetFileInfo (
   IN EFI_FILE_HANDLE            FileHandle\r
   )\r
 {\r
-  EFI_GUID        FileInfoGuid;\r
-  EFI_FILE_INFO   *pFileInfo;\r
-  UINTN           FileInfoSize;\r
-  EFI_STATUS      Status;\r
-\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-\r
-  //\r
-  // Get the required size to allocate\r
-  //\r
-  FileInfoGuid = gEfiFileInfoGuid;\r
-  FileInfoSize = 0;\r
-  pFileInfo = NULL;\r
-  Status = FileHandle->GetInfo(FileHandle, \r
-                               &FileInfoGuid, \r
-                               &FileInfoSize, \r
-                               pFileInfo);\r
-  //\r
-  // error is expected.  getting size to allocate\r
-  //\r
-  ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
-  pFileInfo = AllocateZeroPool(FileInfoSize);\r
-  ASSERT (pFileInfo != NULL);\r
-  //\r
-  // now get the information\r
-  //\r
-  Status = FileHandle->GetInfo(FileHandle, \r
-                               &FileInfoGuid, \r
-                               &FileInfoSize, \r
-                               pFileInfo);\r
-  //\r
-  // if we got an error free the memory and return NULL\r
-  //\r
-  if (EFI_ERROR(Status)) {\r
-    FreePool(pFileInfo);\r
-    return NULL;\r
-  }\r
-  return (pFileInfo);\r
+  return (FileFunctionMap.GetFileInfo(FileHandle));\r
 }\r
 \r
 /**\r
@@ -321,22 +373,7 @@ ShellSetFileInfo (
   IN EFI_FILE_INFO              *FileInfo\r
   )\r
 {\r
-  EFI_GUID        FileInfoGuid;\r
-  \r
-  //\r
-  // ASSERT if the FileHandle or FileInfo is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  ASSERT (FileInfo   != NULL);\r
-\r
-  FileInfoGuid = gEfiFileInfoGuid;\r
-  //\r
-  // Set the info\r
-  //\r
-  return (FileHandle->SetInfo(FileHandle, \r
-                              &FileInfoGuid,\r
-                              (UINTN)FileInfo->Size,\r
-                              FileInfo));\r
+  return (FileFunctionMap.SetFileInfo(FileHandle, FileInfo));\r
 }  \r
   \r
   /**\r
@@ -404,89 +441,90 @@ ShellOpenFileByDevicePath(
     Status = ShellOpenFileByName(FileName, FileHandle, OpenMode, Attributes);\r
     FreePool(FileName);\r
     return (Status);\r
-  } else {\r
+  } \r
+\r
+\r
+  //\r
+  // use old shell method.\r
+  //\r
+  Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, \r
+                                  FilePath, \r
+                                  DeviceHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  Status = gBS->OpenProtocol(*DeviceHandle,\r
+                             &gEfiSimpleFileSystemProtocolGuid,\r
+                             &EfiSimpleFileSystemProtocol,\r
+                             gImageHandle,\r
+                             NULL,\r
+                             EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle);\r
+  if (EFI_ERROR (Status)) {\r
+    FileHandle = NULL;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // go down directories one node at a time.\r
+  //\r
+  while (!IsDevicePathEnd (*FilePath)) {\r
     //\r
-    // use old shell method.\r
+    // For file system access each node should be a file path component\r
     //\r
-    Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, \r
-                                    FilePath, \r
-                                    DeviceHandle);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-    Status = gBS->OpenProtocol(*DeviceHandle,\r
-                               &gEfiSimpleFileSystemProtocolGuid,\r
-                               &EfiSimpleFileSystemProtocol,\r
-                               gImageHandle,\r
-                               NULL,\r
-                               EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
-    if (EFI_ERROR (Status)) {\r
-      return Status;\r
-    }\r
-    Status = EfiSimpleFileSystemProtocol->OpenVolume(EfiSimpleFileSystemProtocol, FileHandle);\r
-    if (EFI_ERROR (Status)) {\r
+    if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||\r
+        DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP\r
+        ) {\r
       FileHandle = NULL;\r
-      return Status;\r
+      return (EFI_INVALID_PARAMETER);\r
     }\r
+    //\r
+    // Open this file path node\r
+    //\r
+    LastHandle  = *FileHandle;\r
+    *FileHandle = NULL;\r
 \r
     //\r
-    // go down directories one node at a time.\r
+    // Try to test opening an existing file\r
     //\r
-    while (!IsDevicePathEnd (*FilePath)) {\r
-      //\r
-      // For file system access each node should be a file path component\r
-      //\r
-      if (DevicePathType    (*FilePath) != MEDIA_DEVICE_PATH ||\r
-          DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP\r
-          ) {\r
-        FileHandle = NULL;\r
-        return (EFI_INVALID_PARAMETER);\r
-      }\r
-      //\r
-      // Open this file path node\r
-      //\r
-      LastHandle  = *FileHandle;\r
-      *FileHandle = NULL;\r
+    Status = LastHandle->Open (\r
+                          LastHandle,\r
+                          FileHandle,\r
+                          ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,\r
+                          OpenMode &~EFI_FILE_MODE_CREATE,\r
+                          0\r
+                          );\r
 \r
-      //\r
-      // Try to test opening an existing file\r
-      //\r
+    //\r
+    // see if the error was that it needs to be created\r
+    //\r
+    if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {\r
       Status = LastHandle->Open (\r
                             LastHandle,\r
                             FileHandle,\r
                             ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,\r
-                            OpenMode &~EFI_FILE_MODE_CREATE,\r
-                            0\r
+                            OpenMode,\r
+                            Attributes\r
                             );\r
+    }\r
+    //\r
+    // Close the last node\r
+    //\r
+    LastHandle->Close (LastHandle);\r
 \r
-      //\r
-      // see if the error was that it needs to be created\r
-      //\r
-      if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) {\r
-        Status = LastHandle->Open (\r
-                              LastHandle,\r
-                              FileHandle,\r
-                              ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName,\r
-                              OpenMode,\r
-                              Attributes\r
-                              );\r
-      }\r
-      //\r
-      // Close the last node\r
-      //\r
-      LastHandle->Close (LastHandle);\r
-\r
-      if (EFI_ERROR(Status)) {\r
-        return (Status);\r
-      }\r
-\r
-      //\r
-      // Get the next node\r
-      //\r
-      *FilePath = NextDevicePathNode (*FilePath);\r
+    if (EFI_ERROR(Status)) {\r
+      return (Status);\r
     }\r
-    return (EFI_SUCCESS);\r
+\r
+    //\r
+    // Get the next node\r
+    //\r
+    *FilePath = NextDevicePathNode (*FilePath);\r
   }\r
+  return (EFI_SUCCESS);\r
 }\r
 \r
 /**\r
@@ -544,6 +582,8 @@ ShellOpenFileByName(
     return (mEfiShellProtocol->OpenFileByName(FileName,\r
                                              FileHandle,\r
                                              OpenMode));\r
+\r
+    ///@todo add the attributes\r
   } \r
   //\r
   // Using EFI Shell version\r
@@ -643,15 +683,7 @@ ShellReadFile(
   OUT VOID                      *Buffer\r
   )\r
 {\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-\r
-  //\r
-  // Perform the read based on EFI_FILE_PROTOCOL\r
-  //\r
-  return (FileHandle->Read(FileHandle, BufferSize, Buffer));\r
+  return (FileFunctionMap.ReadFile(FileHandle, BufferSize, Buffer));\r
 }\r
 \r
 \r
@@ -687,14 +719,7 @@ ShellWriteFile(
   IN VOID                       *Buffer\r
   )\r
 {\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  //\r
-  // Perform the write based on EFI_FILE_PROTOCOL\r
-  //\r
-  return (FileHandle->Write(FileHandle, BufferSize, Buffer));\r
+  return (FileFunctionMap.WriteFile(FileHandle, BufferSize, Buffer));\r
 }\r
 \r
 /** \r
@@ -714,18 +739,7 @@ ShellCloseFile (
   IN EFI_FILE_HANDLE            *FileHandle\r
   )\r
 {\r
-  EFI_STATUS Status;\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  ASSERT (*FileHandle != NULL);\r
-  //\r
-  // Perform the Close based on EFI_FILE_PROTOCOL\r
-  //\r
-  Status = (*FileHandle)->Close(*FileHandle);\r
-  *FileHandle = NULL;\r
-  return Status;\r
+  return (FileFunctionMap.CloseFile(*FileHandle));\r
 }\r
 \r
 /**\r
@@ -748,18 +762,7 @@ ShellDeleteFile (
   IN EFI_FILE_HANDLE           *FileHandle\r
   )\r
 {\r
-  EFI_STATUS Status;\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  ASSERT (*FileHandle != NULL);\r
-  //\r
-  // Perform the Delete based on EFI_FILE_PROTOCOL\r
-  //\r
-  Status = (*FileHandle)->Delete(*FileHandle);\r
-  *FileHandle = NULL;\r
-  return Status;\r
+  return (FileFunctionMap.DeleteFile(*FileHandle));\r
 }\r
 \r
 /**\r
@@ -788,14 +791,7 @@ ShellSetFilePosition (
   IN UINT64            Position\r
   )\r
 {\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  //\r
-  // Perform the SetPosition based on EFI_FILE_PROTOCOL\r
-  //\r
-  return (FileHandle->SetPosition(FileHandle, Position));\r
+  return (FileFunctionMap.SetFilePosition(FileHandle, Position));\r
 }\r
 \r
 /** \r
@@ -820,14 +816,7 @@ ShellGetFilePosition (
   OUT UINT64                    *Position\r
   )\r
 {\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  //\r
-  // Perform the GetPosition based on EFI_FILE_PROTOCOL\r
-  //\r
-  return (FileHandle->GetPosition(FileHandle, Position));\r
+  return (FileFunctionMap.GetFilePosition(FileHandle, Position));\r
 }\r
 /**\r
   Flushes data on a file\r
@@ -849,69 +838,7 @@ ShellFlushFile (
   IN EFI_FILE_HANDLE            FileHandle\r
   )\r
 {\r
-  //\r
-  // ASSERT if FileHandle is NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  //\r
-  // Perform the Flush based on EFI_FILE_PROTOCOL\r
-  //\r
-  return (FileHandle->Flush(FileHandle));\r
-}\r
-\r
-/**\r
-  function to determine if a given handle is a directory handle\r
-\r
-  if DirHandle is NULL then ASSERT()\r
-\r
-  open the file information on the DirHandle and verify that the Attribute\r
-  includes EFI_FILE_DIRECTORY bit set.\r
-\r
-  @param DirHandle              Handle to open file\r
-\r
-  @retval EFI_SUCCESS           DirHandle is a directory\r
-  @retval EFI_INVALID_PARAMETER DirHandle did not have EFI_FILE_INFO available\r
-  @retval EFI_NOT_FOUND         DirHandle is not a directory\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-InternalShellIsDirectory (\r
-  IN EFI_FILE_HANDLE            DirHandle\r
-  )\r
-{\r
-  EFI_FILE_INFO *DirInfo;\r
-\r
-  //\r
-  // ASSERT if DirHandle is NULL\r
-  //\r
-  ASSERT(DirHandle != NULL);\r
-  \r
-  //\r
-  // get the file information for DirHandle\r
-  //\r
-  DirInfo     = ShellGetFileInfo (DirHandle);\r
-  \r
-  //\r
-  // Parse DirInfo\r
-  //\r
-  if (DirInfo == NULL) {\r
-    //\r
-    // We got nothing...\r
-    //\r
-    return (EFI_INVALID_PARAMETER);\r
-  } \r
-  if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {\r
-    //\r
-    // Attributes say this is not a directory\r
-    //\r
-    FreePool (DirInfo);\r
-    return (EFI_NOT_FOUND);\r
-  }\r
-  //\r
-  // all good...\r
-  //\r
-  FreePool (DirInfo);\r
-  return (EFI_SUCCESS);\r
+  return (FileFunctionMap.FlushFile(FileHandle));\r
 }\r
 \r
 /**\r
@@ -936,49 +863,13 @@ EFI_STATUS
 EFIAPI\r
 ShellFindFirstFile (\r
   IN EFI_FILE_HANDLE            DirHandle,\r
-  OUT EFI_FILE_INFO             *Buffer\r
+  OUT EFI_FILE_INFO             **Buffer\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
-  UINTN         BufferSize;\r
-\r
-  //\r
-  // ASSERT if DirHandle is NULL\r
-  //\r
-  ASSERT (DirHandle != NULL);\r
-  \r
-  //\r
-  // verify that DirHandle is a directory\r
-  //\r
-  Status = InternalShellIsDirectory(DirHandle);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
-  } \r
-\r
-  //\r
-  // reset to the begining of the directory \r
-  //\r
-  Status = ShellSetFilePosition (DirHandle, 0);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
-  } \r
-\r
   //\r
-  // Allocate a buffer sized to struct size + enough for the string at the end\r
+  // pass to file handle lib\r
   //\r
-  BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;\r
-  Buffer = AllocateZeroPool(BufferSize);\r
-  ASSERT (Buffer != NULL);\r
-\r
-  //\r
-  // read in the info about the first file\r
-  //\r
-  Status = ShellReadFile (DirHandle, &BufferSize, Buffer);\r
-  ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
-  }\r
-  return (EFI_SUCCESS);\r
+  return (FileHandleFindFirstFile(DirHandle, Buffer));\r
 }\r
 /**\r
   Retrieves the next file in a directory.\r
@@ -1007,47 +898,10 @@ ShellFindNextFile(
   OUT BOOLEAN                    *NoFile\r
   )\r
 {\r
-  EFI_STATUS    Status;\r
-  UINTN         BufferSize;\r
-\r
   //\r
-  // ASSERTs for DirHandle or Buffer or NoFile poitners being NULL\r
+  // pass to file handle lib\r
   //\r
-  ASSERT (DirHandle != NULL);\r
-  ASSERT (Buffer    != NULL);\r
-  ASSERT (NoFile    != NULL);\r
-  \r
-  //\r
-  // verify that DirHandle is a directory\r
-  //\r
-  Status = InternalShellIsDirectory(DirHandle);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
-  } \r
-\r
-  //\r
-  // This BufferSize MUST stay equal to the originally allocated one in GetFirstFile\r
-  //\r
-  BufferSize = FIND_XXXXX_FILE_BUFFER_SIZE;\r
-\r
-  //\r
-  // read in the info about the next file\r
-  //\r
-  Status = ShellReadFile (DirHandle, &BufferSize, Buffer);\r
-  ASSERT(Status != EFI_BUFFER_TOO_SMALL);\r
-  if (EFI_ERROR(Status)) {\r
-    return (Status);\r
-  }\r
-\r
-  //\r
-  // If we read 0 bytes (but did not have erros) we already read in the last file.\r
-  //\r
-  if (BufferSize == 0) {\r
-    FreePool(Buffer);\r
-    *NoFile = TRUE;\r
-  }\r
-\r
-  return (EFI_SUCCESS);\r
+  return (FileHandleFindNextFile(DirHandle, Buffer, NoFile));\r
 }\r
 /**\r
   Retrieve the size of a file.\r
@@ -1071,33 +925,7 @@ ShellGetFileSize (
   OUT UINT64                    *Size\r
   )\r
 {\r
-  EFI_FILE_INFO                 *FileInfo;\r
-\r
-  //\r
-  // ASSERT for FileHandle or Size being NULL\r
-  //\r
-  ASSERT (FileHandle != NULL);\r
-  ASSERT (Size != NULL);\r
-  \r
-  //\r
-  // get the FileInfo structure\r
-  //\r
-  FileInfo = ShellGetFileInfo(FileHandle);\r
-  if (FileInfo == NULL) {\r
-    return (EFI_DEVICE_ERROR);\r
-  }\r
-\r
-  //\r
-  // Assign the Size pointer to the correct value\r
-  //\r
-  *Size = FileInfo->FileSize;\r
-  \r
-  //\r
-  // free the FileInfo memory\r
-  //\r
-  FreePool(FileInfo);\r
-\r
-  return (EFI_SUCCESS);\r
+  return (FileFunctionMap.GetFileSize(FileHandle, Size));\r
 }\r
 /**\r
   Retrieves the status of the break execution flag\r
@@ -1366,7 +1194,7 @@ ShellSetPageBreakMode (
 /// This allows for the struct to be populated.\r
 ///\r
 typedef struct {\r
-  EFI_LIST_ENTRY Link;\r
+  LIST_ENTRY Link;\r
   EFI_STATUS Status;\r
   CHAR16 *FullName;\r
   CHAR16 *FileName;\r
@@ -1390,12 +1218,12 @@ typedef struct {
 LIST_ENTRY*\r
 EFIAPI\r
 InternalShellConvertFileListType (\r
-  EFI_LIST_ENTRY                *FileList\r
+  LIST_ENTRY                *FileList\r
   )\r
 {\r
   LIST_ENTRY                    *ListHead;\r
   SHELL_FILE_ARG                *OldInfo;\r
-  EFI_LIST_ENTRY                *Link;\r
+  LIST_ENTRY                *Link;\r
   EFI_SHELL_FILE_INFO_NO_CONST  *NewInfo;\r
 \r
   //\r
@@ -1406,14 +1234,14 @@ InternalShellConvertFileListType (
   //\r
   // Allocate our list head and initialize the list\r
   //\r
-  ListHead = AllocateZeroPool(sizeof(EFI_LIST_ENTRY));\r
+  ListHead = AllocateZeroPool(sizeof(LIST_ENTRY));\r
   ASSERT (ListHead != NULL);\r
   ListHead = InitializeListHead (ListHead);\r
 \r
   //\r
   // enumerate through each member of the old list and copy\r
   //\r
-  for (Link = FileList->Flink; Link != FileList; Link = Link->Flink) {\r
+  for (Link = FileList->ForwardLink; Link != FileList; Link = Link->ForwardLink) {\r
     OldInfo = CR (Link, SHELL_FILE_ARG, Link, SHELL_FILE_ARG_SIGNATURE);\r
 \r
     //\r
@@ -1435,6 +1263,9 @@ InternalShellConvertFileListType (
     NewInfo->Handle       = OldInfo->Handle;\r
     NewInfo->Status       = OldInfo->Status;\r
 \r
+    // old shell checks for 0 not NULL\r
+    OldInfo->Handle = 0;\r
+\r
     //\r
     // allocate new space to copy strings and structure\r
     //\r
@@ -1497,15 +1328,8 @@ ShellOpenFileMetaArg (
 {\r
   EFI_STATUS                    Status;\r
   LIST_ENTRY                    *EmptyNode;\r
-\r
-  //\r
-  // make sure we have no outstanding list\r
-  //\r
-  if (mOldStyleFileList != NULL) {\r
-    *ListHead = NULL;\r
-    return (EFI_UNSUPPORTED);\r
-  }\r
-\r
+  LIST_ENTRY                    *mOldStyleFileList;\r
+  \r
   //\r
   // ASSERT that Arg and ListHead are not NULL\r
   //\r
@@ -1529,7 +1353,7 @@ ShellOpenFileMetaArg (
   //\r
   // allocate memory for old list head\r
   //\r
-  mOldStyleFileList = (EFI_LIST_ENTRY*)AllocatePool(sizeof(EFI_LIST_ENTRY));\r
+  mOldStyleFileList = (LIST_ENTRY*)AllocatePool(sizeof(LIST_ENTRY));\r
   ASSERT(mOldStyleFileList != NULL);\r
 \r
   //\r
@@ -1551,6 +1375,13 @@ ShellOpenFileMetaArg (
   //\r
   EmptyNode = InternalShellConvertFileListType(mOldStyleFileList);\r
 \r
+  //\r
+  // Free the EFI Shell version that was converted.\r
+  //\r
+  ASSERT_EFI_ERROR(mEfiShellEnvironment2->FreeFileList(mOldStyleFileList));\r
+  FreePool(mOldStyleFileList);\r
+  mOldStyleFileList = NULL;\r
+\r
   //\r
   // remove the empty head of the list\r
   //\r
@@ -1587,19 +1418,13 @@ ShellCloseFileMetaArg (
   if (mEfiShellProtocol != NULL) {\r
     return (mEfiShellProtocol->FreeFileList(ListHead));\r
   } else {\r
-    //\r
-    // Free the EFI Shell version that was converted.\r
-    //\r
-    ASSERT_EFI_ERROR(mEfiShellEnvironment2->FreeFileList(mOldStyleFileList));\r
-    FreePool(mOldStyleFileList);\r
-    mOldStyleFileList = NULL;\r
-\r
     //\r
     // Since this is EFI Shell version we need to free our internally made copy \r
     // of the list\r
     //\r
     for (Node = GetFirstNode((LIST_ENTRY*)*ListHead) ; IsListEmpty((LIST_ENTRY*)*ListHead) == FALSE ; Node = GetFirstNode((LIST_ENTRY*)*ListHead)) {\r
       RemoveEntryList(Node);\r
+      ((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle->Close(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Handle);\r
       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FullName);\r
       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->FileName);\r
       FreePool(((EFI_SHELL_FILE_INFO_NO_CONST*)Node)->Info);\r
@@ -1610,7 +1435,7 @@ ShellCloseFileMetaArg (
 }\r
 \r
 typedef struct {\r
-  EFI_LIST_ENTRY List;\r
+  LIST_ENTRY List;\r
   CHAR16         *Name;\r
   ParamType      Type;\r
   CHAR16         *Value;\r
@@ -1634,7 +1459,7 @@ typedef struct {
 **/\r
 BOOLEAN\r
 EFIAPI\r
-IsCheckList (\r
+InternalIsOnCheckList (\r
   IN CONST CHAR16               *Name,\r
   IN CONST SHELL_PARAM_ITEM     *CheckList,\r
   OUT ParamType                 *Type\r
@@ -1649,6 +1474,15 @@ IsCheckList (
   ASSERT(Type       != NULL);\r
   ASSERT(Name       != NULL);\r
 \r
+  //\r
+  // question mark and page break mode are always supported\r
+  //\r
+  if ((StrCmp(Name, L"-?") == 0) ||\r
+      (StrCmp(Name, L"-b") == 0)\r
+      ) {\r
+     return (TRUE);\r
+  }\r
+\r
   //\r
   // Enumerate through the list\r
   //\r
@@ -1664,7 +1498,7 @@ IsCheckList (
   return (FALSE);\r
 }\r
 /**\r
-  Checks the string for indicators of "flag" status.  this is a leading '/' or '-'\r
+  Checks the string for indicators of "flag" status.  this is a leading '/', '-', or '+'\r
 \r
   @param Name                   pointer to Name of parameter found\r
 \r
@@ -1673,7 +1507,7 @@ IsCheckList (
 **/\r
 BOOLEAN\r
 EFIAPI\r
-IsFlag (\r
+InternalIsFlag (\r
   IN CONST CHAR16               *Name\r
   )\r
 {\r
@@ -1685,7 +1519,10 @@ IsFlag (
   //\r
   // If the Name has a / or - as the first character return TRUE\r
   //\r
-  if ((Name[0] == L'/') || (Name[0] == L'-') ) {\r
+  if ((Name[0] == L'/') || \r
+      (Name[0] == L'-') ||\r
+      (Name[0] == L'+')\r
+      ) {\r
       return (TRUE);\r
   }\r
   return (FALSE);\r
@@ -1699,7 +1536,8 @@ IsFlag (
   @param CheckList              pointer to list of parameters to check\r
   @param CheckPackage           pointer to pointer to list checked values\r
   @param ProblemParam           optional pointer to pointer to unicode string for \r
-                                the paramater that caused failure.\r
+                                the paramater that caused failure.  If used then the\r
+                                caller is responsible for freeing the memory.\r
   @param AutoPageBreak          will automatically set PageBreakEnabled for "b" parameter\r
   @param Argc                   Count of parameters in Argv\r
   @param Argv                   pointer to array of parameters\r
@@ -1774,7 +1612,7 @@ InternalCommandLineParse (
       ASSERT(CurrentItemPackage->Value != NULL);\r
       StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
       InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);\r
-    } else if (IsFlag(Argv[LoopCounter]) == FALSE) {\r
+    } else if (InternalIsFlag(Argv[LoopCounter]) == FALSE) {\r
       //\r
       // add this one as a non-flag\r
       //\r
@@ -1787,7 +1625,7 @@ InternalCommandLineParse (
       StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
       CurrentItemPackage->OriginalPosition = Count++;\r
       InsertTailList(*CheckPackage, (LIST_ENTRY*)CurrentItemPackage);\r
-    } else if (IsCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {\r
+    } else if (InternalIsOnCheckList(Argv[LoopCounter], CheckList, &CurrentItemType) == TRUE) {\r
       //\r
       // this is a flag\r
       //\r
@@ -1818,7 +1656,9 @@ InternalCommandLineParse (
       //\r
       // this was a non-recognised flag... error!\r
       //\r
-      *ProblemParam = (CHAR16*)Argv[LoopCounter];\r
+      *ProblemParam = AllocatePool(StrSize(Argv[LoopCounter]));\r
+      ASSERT(*ProblemParam != NULL);\r
+      StrCpy(*ProblemParam, Argv[LoopCounter]);\r
       ShellCommandLineFreeVarList(*CheckPackage);\r
       *CheckPackage = NULL;\r
       return (EFI_VOLUME_CORRUPTED);\r