]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLib/UefiShellLib.c
ShellPkg: Fix memory leak in 'ShellOpenFileByName'.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
index 10c6b592fdf10e872898d254d05c3df0a04a907e..9e815c56a6c8f7106965c04de1c90397ba465c7f 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Provides interface to shell functionality for shell commands and applications.\r
 \r
-  Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>\r
   This program and the accompanying materials\r
   are licensed and made available under the terms and conditions of the BSD License\r
   which accompanies this distribution.  The full text of the license may be found at\r
@@ -15,6 +15,7 @@
 #include "UefiShellLib.h"\r
 #include <ShellBase.h>\r
 #include <Library/SortLib.h>\r
+#include <Library/BaseLib.h>\r
 \r
 #define FIND_XXXXX_FILE_BUFFER_SIZE (SIZE_OF_EFI_FILE_INFO + MAX_FILE_NAME_LEN)\r
 \r
@@ -671,6 +672,8 @@ ShellOpenFileByName(
   EFI_DEVICE_PATH_PROTOCOL      *FilePath;\r
   EFI_STATUS                    Status;\r
   EFI_FILE_INFO                 *FileInfo;\r
+  CHAR16                        *FileNameCopy;\r
+  EFI_STATUS                    Status2;\r
 \r
   //\r
   // ASSERT if FileName is NULL\r
@@ -682,11 +685,33 @@ ShellOpenFileByName(
   }\r
 \r
   if (gEfiShellProtocol != NULL) {\r
-    if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE && (Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {\r
-      return ShellCreateDirectory(FileName, FileHandle);\r
+    if ((OpenMode & EFI_FILE_MODE_CREATE) == EFI_FILE_MODE_CREATE) {\r
+\r
+      //\r
+      // Create only a directory\r
+      //\r
+      if ((Attributes & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {\r
+        return ShellCreateDirectory(FileName, FileHandle);\r
+      }\r
+\r
+      //\r
+      // Create the directory to create the file in\r
+      //\r
+      FileNameCopy = AllocateCopyPool (StrSize (FileName), FileName);\r
+      if (FileName == NULL) {\r
+        return (EFI_OUT_OF_RESOURCES);\r
+      }\r
+      PathCleanUpDirectories (FileNameCopy);\r
+      if (PathRemoveLastItem (FileNameCopy)) {\r
+        if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {\r
+          ShellCloseFile (FileHandle);\r
+        }\r
+      }\r
+      SHELL_FREE_NON_NULL (FileNameCopy);\r
     }\r
+\r
     //\r
-    // Use UEFI Shell 2.0 method\r
+    // Use UEFI Shell 2.0 method to create the file\r
     //\r
     Status = gEfiShellProtocol->OpenFileByName(FileName,\r
                                                FileHandle,\r
@@ -695,8 +720,12 @@ ShellOpenFileByName(
       FileInfo = FileFunctionMap.GetFileInfo(*FileHandle);\r
       ASSERT(FileInfo != NULL);\r
       FileInfo->Attribute = Attributes;\r
-      Status = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);\r
+      Status2 = FileFunctionMap.SetFileInfo(*FileHandle, FileInfo);\r
       FreePool(FileInfo);\r
+      if (EFI_ERROR (Status2)) {\r
+        gEfiShellProtocol->CloseFile(*FileHandle);\r
+      }\r
+      Status = Status2;\r
     }\r
     return (Status);\r
   }\r
@@ -1175,7 +1204,7 @@ ShellSetEnvironmentVariable (
   The CommandLine is executed from the current working directory on the current\r
   device.\r
 \r
-  The EnvironmentVariables and Status parameters are ignored in a pre-UEFI Shell 2.0\r
+  The EnvironmentVariables pararemeter is ignored in a pre-UEFI Shell 2.0\r
   environment.  The values pointed to by the parameters will be unchanged by the\r
   ShellExecute() function.  The Output parameter has no effect in a\r
   UEFI Shell 2.0 environment.\r
@@ -1203,6 +1232,7 @@ ShellExecute (
   OUT EFI_STATUS                *Status OPTIONAL\r
   )\r
 {\r
+  EFI_STATUS                CmdStatus;\r
   //\r
   // Check for UEFI Shell 2.0 protocols\r
   //\r
@@ -1221,16 +1251,29 @@ ShellExecute (
   //\r
   if (mEfiShellEnvironment2 != NULL) {\r
     //\r
-    // Call EFI Shell version (not using EnvironmentVariables or Status parameters)\r
+    // Call EFI Shell version.\r
     // Due to oddity in the EFI shell we want to dereference the ParentHandle here\r
     //\r
-    return (mEfiShellEnvironment2->Execute(*ParentHandle,\r
+    CmdStatus = (mEfiShellEnvironment2->Execute(*ParentHandle,\r
                                           CommandLine,\r
                                           Output));\r
+    //\r
+    // No Status output parameter so just use the returned status\r
+    //\r
+    if (Status != NULL) {\r
+      *Status = CmdStatus;\r
+    }\r
+    //\r
+    // If there was an error, we can't tell if it was from the command or from\r
+    // the Execute() function, so we'll just assume the shell ran successfully\r
+    // and the error came from the command.\r
+    //\r
+    return EFI_SUCCESS;\r
   }\r
 \r
   return (EFI_UNSUPPORTED);\r
 }\r
+\r
 /**\r
   Retreives the current directory path\r
 \r
@@ -1238,6 +1281,8 @@ ShellExecute (
   name. If the DeviceName is not NULL, it returns the current directory name\r
   on specified drive.\r
 \r
+  Note that the current directory string should exclude the tailing backslash character.\r
+\r
   @param DeviceName             the name of the drive to get directory on\r
 \r
   @retval NULL                  the directory does not exist\r
@@ -1416,26 +1461,30 @@ InternalShellConvertFileListType (
     //\r
     // allocate new space to copy strings and structure\r
     //\r
-    NewInfo->FullName     = AllocateZeroPool(StrSize(OldInfo->FullName));\r
-    NewInfo->FileName     = AllocateZeroPool(StrSize(OldInfo->FileName));\r
-    NewInfo->Info         = AllocateZeroPool((UINTN)OldInfo->Info->Size);\r
+    NewInfo->FullName     = AllocateCopyPool(StrSize(OldInfo->FullName), OldInfo->FullName);\r
+    NewInfo->FileName     = AllocateCopyPool(StrSize(OldInfo->FileName), OldInfo->FileName);\r
+    NewInfo->Info         = AllocateCopyPool((UINTN)OldInfo->Info->Size, OldInfo->Info);\r
 \r
     //\r
     // make sure all the memory allocations were sucessful\r
     //\r
     if (NULL == NewInfo->FullName || NewInfo->FileName == NULL || NewInfo->Info == NULL) {\r
+      //\r
+      // Free the partially allocated new node\r
+      //\r
+      SHELL_FREE_NON_NULL(NewInfo->FullName);\r
+      SHELL_FREE_NON_NULL(NewInfo->FileName);\r
+      SHELL_FREE_NON_NULL(NewInfo->Info);\r
+      SHELL_FREE_NON_NULL(NewInfo);\r
+\r
+      //\r
+      // Free the previously converted stuff\r
+      //\r
       ShellCloseFileMetaArg((EFI_SHELL_FILE_INFO**)(&ListHead));\r
       ListHead = NULL;\r
       break;\r
     }\r
 \r
-    //\r
-    // Copt the strings and structure\r
-    //\r
-    StrCpy(NewInfo->FullName, OldInfo->FullName);\r
-    StrCpy(NewInfo->FileName, OldInfo->FileName);\r
-    gBS->CopyMem (NewInfo->Info, OldInfo->Info, (UINTN)OldInfo->Info->Size);\r
-\r
     //\r
     // add that to the list\r
     //\r
@@ -1447,8 +1496,8 @@ InternalShellConvertFileListType (
   Opens a group of files based on a path.\r
 \r
   This function uses the Arg to open all the matching files. Each matched\r
-  file has a SHELL_FILE_ARG structure to record the file information. These\r
-  structures are placed on the list ListHead. Users can get the SHELL_FILE_ARG\r
+  file has a SHELL_FILE_INFO structure to record the file information. These\r
+  structures are placed on the list ListHead. Users can get the SHELL_FILE_INFO\r
   structures from ListHead to access each file. This function supports wildcards\r
   and will process '?' and '*' as such.  the list must be freed with a call to\r
   ShellCloseFileMetaArg().\r
@@ -1476,6 +1525,7 @@ ShellOpenFileMetaArg (
 {\r
   EFI_STATUS                    Status;\r
   LIST_ENTRY                    mOldStyleFileList;\r
+  CHAR16                        *CleanFilePathStr;\r
 \r
   //\r
   // ASSERT that Arg and ListHead are not NULL\r
@@ -1483,6 +1533,13 @@ ShellOpenFileMetaArg (
   ASSERT(Arg      != NULL);\r
   ASSERT(ListHead != NULL);\r
 \r
+  CleanFilePathStr = NULL;\r
+\r
+  Status = InternalShellStripQuotes (Arg, &CleanFilePathStr);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
   // Check for UEFI Shell 2.0 protocols\r
   //\r
@@ -1490,11 +1547,12 @@ ShellOpenFileMetaArg (
     if (*ListHead == NULL) {\r
       *ListHead = (EFI_SHELL_FILE_INFO*)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
       if (*ListHead == NULL) {\r
+        FreePool(CleanFilePathStr);\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
       InitializeListHead(&((*ListHead)->Link));\r
     }\r
-    Status = gEfiShellProtocol->OpenFileList(Arg,\r
+    Status = gEfiShellProtocol->OpenFileList(CleanFilePathStr,\r
                                            OpenMode,\r
                                            ListHead);\r
     if (EFI_ERROR(Status)) {\r
@@ -1504,9 +1562,11 @@ ShellOpenFileMetaArg (
     }\r
     if (*ListHead != NULL && IsListEmpty(&(*ListHead)->Link)) {\r
       FreePool(*ListHead);\r
+      FreePool(CleanFilePathStr);\r
       *ListHead = NULL;\r
       return (EFI_NOT_FOUND);\r
     }\r
+    FreePool(CleanFilePathStr);\r
     return (Status);\r
   }\r
 \r
@@ -1522,15 +1582,17 @@ ShellOpenFileMetaArg (
     //\r
     // Get the EFI Shell list of files\r
     //\r
-    Status = mEfiShellEnvironment2->FileMetaArg(Arg, &mOldStyleFileList);\r
+    Status = mEfiShellEnvironment2->FileMetaArg(CleanFilePathStr, &mOldStyleFileList);\r
     if (EFI_ERROR(Status)) {\r
       *ListHead = NULL;\r
+      FreePool(CleanFilePathStr);\r
       return (Status);\r
     }\r
 \r
     if (*ListHead == NULL) {\r
       *ListHead = (EFI_SHELL_FILE_INFO    *)AllocateZeroPool(sizeof(EFI_SHELL_FILE_INFO));\r
       if (*ListHead == NULL) {\r
+        FreePool(CleanFilePathStr);\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
       InitializeListHead(&((*ListHead)->Link));\r
@@ -1551,9 +1613,11 @@ ShellOpenFileMetaArg (
       *ListHead = NULL;\r
       Status = EFI_NOT_FOUND;\r
     }\r
+    FreePool(CleanFilePathStr);\r
     return (Status);\r
   }\r
 \r
+  FreePool(CleanFilePathStr);\r
   return (EFI_UNSUPPORTED);\r
 }\r
 /**\r
@@ -1651,14 +1715,15 @@ ShellFindFilePath (
 \r
   Path = ShellGetEnvironmentVariable(L"cwd");\r
   if (Path != NULL) {\r
-    Size = StrSize(Path);\r
+    Size = StrSize(Path) + sizeof(CHAR16);\r
     Size += StrSize(FileName);\r
     TestPath = AllocateZeroPool(Size);\r
     if (TestPath == NULL) {\r
       return (NULL);\r
     }\r
-    StrCpy(TestPath, Path);\r
-    StrCat(TestPath, FileName);\r
+    StrCpyS(TestPath, Size/sizeof(CHAR16), Path);\r
+    StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");\r
+    StrCatS(TestPath, Size/sizeof(CHAR16), FileName);\r
     Status = ShellOpenFileByName(TestPath, &Handle, EFI_FILE_MODE_READ, 0);\r
     if (!EFI_ERROR(Status)){\r
       if (FileHandleIsDirectory(Handle) != EFI_SUCCESS) {\r
@@ -1690,12 +1755,12 @@ ShellFindFilePath (
           *TempChar = CHAR_NULL;\r
         }\r
         if (TestPath[StrLen(TestPath)-1] != L'\\') {\r
-          StrCat(TestPath, L"\\");\r
+          StrCatS(TestPath, Size/sizeof(CHAR16), L"\\");\r
         }\r
         if (FileName[0] == L'\\') {\r
           FileName++;\r
         }\r
-        StrCat(TestPath, FileName);\r
+        StrCatS(TestPath, Size/sizeof(CHAR16), FileName);\r
         if (StrStr(Walker, L";") != NULL) {\r
           Walker = StrStr(Walker, L";") + 1;\r
         } else {\r
@@ -1764,9 +1829,9 @@ ShellFindFilePathEx (
     return (NULL);\r
   }\r
   for (ExtensionWalker = FileExtension, TempChar2 = (CHAR16*)FileExtension;  TempChar2 != NULL ; ExtensionWalker = TempChar2 + 1){\r
-    StrCpy(TestPath, FileName);\r
+    StrCpyS(TestPath, Size/sizeof(CHAR16), FileName);\r
     if (ExtensionWalker != NULL) {\r
-      StrCat(TestPath, ExtensionWalker);\r
+      StrCatS(TestPath, Size/sizeof(CHAR16), ExtensionWalker);\r
     }\r
     TempChar = StrStr(TestPath, L";");\r
     if (TempChar != NULL) {\r
@@ -1870,6 +1935,7 @@ InternalIsOnCheckList (
 \r
   @param[in] Name               pointer to Name of parameter found\r
   @param[in] AlwaysAllowNumbers TRUE to allow numbers, FALSE to not.\r
+  @param[in] TimeNumbers        TRUE to allow numbers with ":", FALSE otherwise.\r
 \r
   @retval TRUE                  the Parameter is a flag.\r
   @retval FALSE                 the Parameter not a flag.\r
@@ -1878,7 +1944,8 @@ BOOLEAN
 EFIAPI\r
 InternalIsFlag (\r
   IN CONST CHAR16               *Name,\r
-  IN BOOLEAN                    AlwaysAllowNumbers\r
+  IN CONST BOOLEAN              AlwaysAllowNumbers,\r
+  IN CONST BOOLEAN              TimeNumbers\r
   )\r
 {\r
   //\r
@@ -1889,7 +1956,7 @@ InternalIsFlag (
   //\r
   // If we accept numbers then dont return TRUE. (they will be values)\r
   //\r
-  if (((Name[0] == L'-' || Name[0] == L'+') && ShellIsHexaDecimalDigitCharacter(Name[1])) && AlwaysAllowNumbers) {\r
+  if (((Name[0] == L'-' || Name[0] == L'+') && InternalShellIsHexOrDecimalNumber(Name+1, FALSE, FALSE, TimeNumbers)) && AlwaysAllowNumbers) {\r
     return (FALSE);\r
   }\r
 \r
@@ -1949,6 +2016,7 @@ InternalCommandLineParse (
   UINTN                         ValueSize;\r
   UINTN                         Count;\r
   CONST CHAR16                  *TempPointer;\r
+  UINTN                         CurrentValueSize;\r
 \r
   CurrentItemPackage = NULL;\r
   GetItemValue = 0;\r
@@ -2004,13 +2072,12 @@ InternalCommandLineParse (
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      CurrentItemPackage->Name  = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
+      CurrentItemPackage->Name  = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
       if (CurrentItemPackage->Name == NULL) {\r
         ShellCommandLineFreeVarList(*CheckPackage);\r
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      StrCpy(CurrentItemPackage->Name,  Argv[LoopCounter]);\r
       CurrentItemPackage->Type  = CurrentItemType;\r
       CurrentItemPackage->OriginalPosition = (UINTN)(-1);\r
       CurrentItemPackage->Value = NULL;\r
@@ -2023,6 +2090,7 @@ InternalCommandLineParse (
         // possibly trigger the next loop(s) to populate the value of this item\r
         //\r
         case TypeValue:\r
+        case TypeTimeValue:\r
           GetItemValue = 1;\r
           ValueSize = 0;\r
           break;\r
@@ -2042,44 +2110,35 @@ InternalCommandLineParse (
           ASSERT(GetItemValue == 0);\r
           break;\r
       }\r
-    } else if (GetItemValue != 0 && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers)) {\r
-      ASSERT(CurrentItemPackage != NULL);\r
+    } else if (GetItemValue != 0 && CurrentItemPackage != NULL && !InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, (BOOLEAN)(CurrentItemPackage->Type == TypeTimeValue))) {\r
       //\r
       // get the item VALUE for a previous flag\r
       //\r
-      if (StrStr(Argv[LoopCounter], L" ") == NULL) {\r
-        CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16), CurrentItemPackage->Value);\r
-        ASSERT(CurrentItemPackage->Value != NULL);\r
-        if (ValueSize == 0) {\r
-          StrCpy(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-        } else {\r
-          StrCat(CurrentItemPackage->Value, L" ");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-        }\r
-        ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+      CurrentValueSize = ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+      CurrentItemPackage->Value = ReallocatePool(ValueSize, CurrentValueSize, CurrentItemPackage->Value);\r
+      ASSERT(CurrentItemPackage->Value != NULL);\r
+      if (ValueSize == 0) {\r
+        StrCpyS( CurrentItemPackage->Value, \r
+                  CurrentValueSize/sizeof(CHAR16), \r
+                  Argv[LoopCounter]\r
+                  );\r
       } else {\r
-        //\r
-        // the parameter has spaces.  must be quoted.\r
-        //\r
-        CurrentItemPackage->Value = ReallocatePool(ValueSize, ValueSize + StrSize(Argv[LoopCounter]) + sizeof(CHAR16) + sizeof(CHAR16) + sizeof(CHAR16), CurrentItemPackage->Value);\r
-        ASSERT(CurrentItemPackage->Value != NULL);\r
-        if (ValueSize == 0) {\r
-          StrCpy(CurrentItemPackage->Value, L"\"");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
-        } else {\r
-          StrCat(CurrentItemPackage->Value, L" ");\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
-          StrCat(CurrentItemPackage->Value, Argv[LoopCounter]);\r
-          StrCat(CurrentItemPackage->Value, L"\"");\r
-       }\r
-        ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+        StrCatS( CurrentItemPackage->Value, \r
+                  CurrentValueSize/sizeof(CHAR16), \r
+                  L" "\r
+                  );\r
+        StrCatS( CurrentItemPackage->Value, \r
+                  CurrentValueSize/sizeof(CHAR16), \r
+                  Argv[LoopCounter]\r
+                  );\r
       }\r
+      ValueSize += StrSize(Argv[LoopCounter]) + sizeof(CHAR16);\r
+      \r
       GetItemValue--;\r
       if (GetItemValue == 0) {\r
         InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
       }\r
-    } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers) ){ //|| ProblemParam == NULL) {\r
+    } else if (!InternalIsFlag(Argv[LoopCounter], AlwaysAllowNumbers, FALSE)){\r
       //\r
       // add this one as a non-flag\r
       //\r
@@ -2099,13 +2158,12 @@ InternalCommandLineParse (
       }\r
       CurrentItemPackage->Name  = NULL;\r
       CurrentItemPackage->Type  = TypePosition;\r
-      CurrentItemPackage->Value = AllocateZeroPool(StrSize(TempPointer));\r
+      CurrentItemPackage->Value = AllocateCopyPool(StrSize(TempPointer), TempPointer);\r
       if (CurrentItemPackage->Value == NULL) {\r
         ShellCommandLineFreeVarList(*CheckPackage);\r
         *CheckPackage = NULL;\r
         return (EFI_OUT_OF_RESOURCES);\r
       }\r
-      StrCpy(CurrentItemPackage->Value, TempPointer);\r
       CurrentItemPackage->OriginalPosition = Count++;\r
       InsertHeadList(*CheckPackage, &CurrentItemPackage->Link);\r
     } else {\r
@@ -2113,10 +2171,7 @@ InternalCommandLineParse (
       // this was a non-recognised flag... error!\r
       //\r
       if (ProblemParam != NULL) {\r
-        *ProblemParam = AllocateZeroPool(StrSize(Argv[LoopCounter]));\r
-        if (*ProblemParam != NULL) {\r
-          StrCpy(*ProblemParam, Argv[LoopCounter]);\r
-        }\r
+        *ProblemParam = AllocateCopyPool(StrSize(Argv[LoopCounter]), Argv[LoopCounter]);\r
       }\r
       ShellCommandLineFreeVarList(*CheckPackage);\r
       *CheckPackage = NULL;\r
@@ -2475,7 +2530,7 @@ ShellCommandLineGetCount(
 }\r
 \r
 /**\r
-  Determins if a parameter is duplicated.\r
+  Determines if a parameter is duplicated.\r
 \r
   If Param is not NULL then it will point to a callee allocated string buffer\r
   with the parameter value if a duplicate is found.\r
@@ -2583,7 +2638,7 @@ ShellCopySearchAndReplace(
   if (Replace == NULL) {\r
     return (EFI_OUT_OF_RESOURCES);\r
   }\r
-  NewString = SetMem16(NewString, NewSize, CHAR_NULL);\r
+  NewString = ZeroMem(NewString, NewSize);\r
   while (*SourceString != CHAR_NULL) {\r
     //\r
     // if we find the FindTarget and either Skip == FALSE or Skip  and we\r
@@ -2598,14 +2653,14 @@ ShellCopySearchAndReplace(
         FreePool(Replace);\r
         return (EFI_BUFFER_TOO_SMALL);\r
       }\r
-      StrCat(NewString, Replace);\r
+      StrCatS(NewString, NewSize/sizeof(CHAR16), Replace);\r
     } else {\r
       Size = StrSize(NewString);\r
       if (Size + sizeof(CHAR16) > NewSize) {\r
         FreePool(Replace);\r
         return (EFI_BUFFER_TOO_SMALL);\r
       }\r
-      StrnCat(NewString, SourceString, 1);\r
+      StrnCatS(NewString, NewSize/sizeof(CHAR16), SourceString, 1);\r
       SourceString++;\r
     }\r
   }\r
@@ -3103,7 +3158,7 @@ ShellStrToUintn(
 \r
   Hex = FALSE;\r
 \r
-  if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE)) {\r
+  if (!InternalShellIsHexOrDecimalNumber(String, Hex, TRUE, FALSE)) {\r
     Hex = TRUE;\r
   }\r
 \r
@@ -3208,7 +3263,8 @@ StrnCatGrow (
       *CurrentSize = NewSize;\r
     }\r
   } else {\r
-    *Destination = AllocateZeroPool((Count+1)*sizeof(CHAR16));\r
+    NewSize = (Count+1)*sizeof(CHAR16);\r
+    *Destination = AllocateZeroPool(NewSize);\r
   }\r
 \r
   //\r
@@ -3217,7 +3273,9 @@ StrnCatGrow (
   if (*Destination == NULL) {\r
     return (NULL);\r
   }\r
-  return StrnCat(*Destination, Source, Count);\r
+  \r
+  StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);\r
+  return *Destination;\r
 }\r
 \r
 /**\r
@@ -3520,6 +3578,7 @@ ShellPromptForResponseHii (
   @param[in] String       The string to evaluate.\r
   @param[in] ForceHex     TRUE - always assume hex.\r
   @param[in] StopAtSpace  TRUE to halt upon finding a space, FALSE to keep going.\r
+  @param[in] TimeNumbers        TRUE to allow numbers with ":", FALSE otherwise.\r
 \r
   @retval TRUE        It is all numeric (dec/hex) characters.\r
   @retval FALSE       There is a non-numeric character.\r
@@ -3529,7 +3588,8 @@ EFIAPI
 InternalShellIsHexOrDecimalNumber (\r
   IN CONST CHAR16   *String,\r
   IN CONST BOOLEAN  ForceHex,\r
-  IN CONST BOOLEAN  StopAtSpace\r
+  IN CONST BOOLEAN  StopAtSpace,\r
+  IN CONST BOOLEAN  TimeNumbers\r
   )\r
 {\r
   BOOLEAN Hex;\r
@@ -3573,6 +3633,9 @@ InternalShellIsHexOrDecimalNumber (
   // loop through the remaining characters and use the lib function\r
   //\r
   for ( ; String != NULL && *String != CHAR_NULL && !(StopAtSpace && *String == L' ') ; String++){\r
+    if (TimeNumbers && (String[0] == L':')) {\r
+      continue;\r
+    }\r
     if (Hex) {\r
       if (!ShellIsHexaDecimalDigitCharacter(*String)) {\r
         return (FALSE);\r
@@ -3675,7 +3738,7 @@ InternalShellHexCharToUintn (
 /**\r
   Convert a Null-terminated Unicode hexadecimal string to a value of type UINT64.\r
 \r
-  This function returns a value of type UINTN by interpreting the contents\r
+  This function returns a value of type UINT64 by interpreting the contents\r
   of the Unicode string specified by String as a hexadecimal number.\r
   The format of the input Unicode string String is:\r
 \r
@@ -3743,16 +3806,16 @@ InternalShellStrHexToUint64 (
   Result = 0;\r
 \r
   //\r
-  // Skip spaces if requested\r
+  // there is a space where there should't be\r
   //\r
-  while (StopAtSpace && *String == L' ') {\r
-    String++;\r
+  if (*String == L' ') {\r
+    return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
   while (ShellIsHexaDecimalDigitCharacter (*String)) {\r
     //\r
     // If the Hex Number represented by String overflows according\r
-    // to the range defined by UINTN, then ASSERT().\r
+    // to the range defined by UINT64, then return EFI_DEVICE_ERROR.\r
     //\r
     if (!(Result <= (RShiftU64((((UINT64) ~0) - InternalShellHexCharToUintn (*String)), 4)))) {\r
 //    if (!(Result <= ((((UINT64) ~0) - InternalShellHexCharToUintn (*String)) >> 4))) {\r
@@ -3835,15 +3898,18 @@ InternalShellStrDecimalToUint64 (
   Result = 0;\r
 \r
   //\r
-  // Skip spaces if requested\r
+  // Stop upon space if requested \r
+  // (if the whole value was 0)\r
   //\r
-  while (StopAtSpace && *String == L' ') {\r
-    String++;\r
+  if (StopAtSpace && *String == L' ') {\r
+    *Value = Result;\r
+    return (EFI_SUCCESS);\r
   }\r
+\r
   while (ShellIsDecimalDigitCharacter (*String)) {\r
     //\r
     // If the number represented by String overflows according\r
-    // to the range defined by UINT64, then ASSERT().\r
+    // to the range defined by UINT64, then return EFI_DEVICE_ERROR.\r
     //\r
 \r
     if (!(Result <= (DivU64x32((((UINT64) ~0) - (*String - L'0')),10)))) {\r
@@ -3896,10 +3962,10 @@ ShellConvertStringToUint64(
 \r
   Hex = ForceHex;\r
 \r
-  if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace)) {\r
+  if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {\r
     if (!Hex) {\r
       Hex = TRUE;\r
-      if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace)) {\r
+      if (!InternalShellIsHexOrDecimalNumber(String, Hex, StopAtSpace, FALSE)) {\r
         return (EFI_INVALID_PARAMETER);\r
       }\r
     } else {\r
@@ -3915,7 +3981,7 @@ ShellConvertStringToUint64(
   //\r
   // make sure we have something left that is numeric.\r
   //\r
-  if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace)) {\r
+  if (Walker == NULL || *Walker == CHAR_NULL || !InternalShellIsHexOrDecimalNumber(Walker, Hex, StopAtSpace, FALSE)) {\r
     return (EFI_INVALID_PARAMETER);\r
   }\r
 \r
@@ -4224,3 +4290,41 @@ ShellDeleteFileByName(
   return(Status);\r
   \r
 }\r
+\r
+/**\r
+  Cleans off all the quotes in the string.\r
+\r
+  @param[in]     OriginalString   pointer to the string to be cleaned.\r
+  @param[out]   CleanString      The new string with all quotes removed. \r
+                                                  Memory allocated in the function and free \r
+                                                  by caller.\r
+\r
+  @retval EFI_SUCCESS   The operation was successful.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+InternalShellStripQuotes (\r
+  IN  CONST CHAR16     *OriginalString,\r
+  OUT CHAR16           **CleanString\r
+  )\r
+{\r
+  CHAR16            *Walker;\r
+  \r
+  if (OriginalString == NULL || CleanString == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *CleanString = AllocateCopyPool (StrSize (OriginalString), OriginalString);\r
+  if (*CleanString == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  for (Walker = *CleanString; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {\r
+    if (*Walker == L'\"') {\r
+      CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r