]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLib/UefiShellLib.c
Merge branch 'master' of https://github.com/tianocore/edk2
[mirror_edk2.git] / ShellPkg / Library / UefiShellLib / UefiShellLib.c
index 5b4c6d3fb7e392468aa1a79b79c193779d865d48..dac0524fcbdd98652f4fb43368290b1bada372e4 100644 (file)
@@ -1,6 +1,7 @@
 /** @file\r
   Provides interface to shell functionality for shell commands and applications.\r
 \r
+  Copyright 2016 Dell Inc.\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
@@ -673,6 +674,7 @@ ShellOpenFileByName(
   EFI_STATUS                    Status;\r
   EFI_FILE_INFO                 *FileInfo;\r
   CHAR16                        *FileNameCopy;\r
+  EFI_STATUS                    Status2;\r
 \r
   //\r
   // ASSERT if FileName is NULL\r
@@ -702,8 +704,9 @@ ShellOpenFileByName(
       }\r
       PathCleanUpDirectories (FileNameCopy);\r
       if (PathRemoveLastItem (FileNameCopy)) {\r
-        ShellCreateDirectory (FileNameCopy, FileHandle);\r
-        ShellCloseFile (FileHandle);\r
+        if (!EFI_ERROR(ShellCreateDirectory (FileNameCopy, FileHandle))) {\r
+          ShellCloseFile (FileHandle);\r
+        }\r
       }\r
       SHELL_FREE_NON_NULL (FileNameCopy);\r
     }\r
@@ -718,8 +721,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
@@ -1275,6 +1282,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
@@ -1707,13 +1716,14 @@ 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
     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
@@ -2521,7 +2531,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
@@ -3254,7 +3264,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
@@ -3264,7 +3275,7 @@ StrnCatGrow (
     return (NULL);\r
   }\r
   \r
-  StrCatS(*Destination, Count + 1, Source);\r
+  StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, Count);\r
   return *Destination;\r
 }\r
 \r
@@ -3728,7 +3739,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
@@ -3796,16 +3807,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
@@ -3888,15 +3899,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
@@ -4070,9 +4084,20 @@ ShellFileHandleReturnLine(
   If the position upon start is 0, then the Ascii Boolean will be set.  This should be\r
   maintained and not changed for all operations with the same file.\r
 \r
+  NOTE: LINES THAT ARE RETURNED BY THIS FUNCTION ARE UCS2, EVEN IF THE FILE BEING READ\r
+        IS IN ASCII FORMAT.\r
+\r
   @param[in]       Handle        SHELL_FILE_HANDLE to read from.\r
-  @param[in, out]  Buffer        The pointer to buffer to read into.\r
-  @param[in, out]  Size          The pointer to number of bytes in Buffer.\r
+  @param[in, out]  Buffer        The pointer to buffer to read into. If this function\r
+                                 returns EFI_SUCCESS, then on output Buffer will\r
+                                 contain a UCS2 string, even if the file being\r
+                                 read is ASCII.\r
+  @param[in, out]  Size          On input, pointer to number of bytes in Buffer.\r
+                                 On output, unchanged unless Buffer is too small\r
+                                 to contain the next line of the file. In that\r
+                                 case Size is set to the number of bytes needed\r
+                                 to hold the next line of the file (as a UCS2\r
+                                 string, even if it is an ASCII file).\r
   @param[in]       Truncate      If the buffer is large enough, this has no effect.\r
                                  If the buffer is is too small and Truncate is TRUE,\r
                                  the line will be truncated.\r
@@ -4084,6 +4109,7 @@ ShellFileHandleReturnLine(
 \r
   @retval EFI_SUCCESS           The operation was successful.  The line is stored in\r
                                 Buffer.\r
+  @retval EFI_END_OF_FILE       There are no more lines in the file.\r
   @retval EFI_INVALID_PARAMETER Handle was NULL.\r
   @retval EFI_INVALID_PARAMETER Size was NULL.\r
   @retval EFI_BUFFER_TOO_SMALL  Size was not large enough to store the line.\r
@@ -4129,45 +4155,64 @@ ShellFileHandleReadLine(
     }\r
   }\r
 \r
+  if (*Ascii) {\r
+    CharSize = sizeof(CHAR8);\r
+  } else {\r
+    CharSize = sizeof(CHAR16);\r
+  }\r
   for (CountSoFar = 0;;CountSoFar++){\r
     CharBuffer = 0;\r
-    if (*Ascii) {\r
-      CharSize = sizeof(CHAR8);\r
-    } else {\r
-      CharSize = sizeof(CHAR16);\r
-    }\r
     Status = gEfiShellProtocol->ReadFile(Handle, &CharSize, &CharBuffer);\r
     if (  EFI_ERROR(Status)\r
        || CharSize == 0\r
        || (CharBuffer == L'\n' && !(*Ascii))\r
        || (CharBuffer ==  '\n' && *Ascii)\r
      ){\r
+      if (CharSize == 0) {\r
+        Status = EFI_END_OF_FILE;\r
+      }\r
       break;\r
     }\r
     //\r
     // if we have space save it...\r
     //\r
-    if ((CountSoFar+1)*sizeof(CHAR16) < *Size){\r
+    if ((CountSoFar + 1) * CharSize < *Size){\r
       ASSERT(Buffer != NULL);\r
-      ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
-      ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
+      if (*Ascii) {\r
+        ((CHAR8*)Buffer)[CountSoFar] = (CHAR8) CharBuffer;\r
+        ((CHAR8*)Buffer)[CountSoFar+1] = '\0';\r
+      }\r
+      else {\r
+        ((CHAR16*)Buffer)[CountSoFar] = CharBuffer;\r
+        ((CHAR16*)Buffer)[CountSoFar+1] = CHAR_NULL;\r
+      }\r
     }\r
   }\r
 \r
   //\r
   // if we ran out of space tell when...\r
   //\r
-  if ((CountSoFar+1)*sizeof(CHAR16) > *Size){\r
-    *Size = (CountSoFar+1)*sizeof(CHAR16);\r
-    if (!Truncate) {\r
-      gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
-    } else {\r
-      DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
+  if (Status != EFI_END_OF_FILE){\r
+    if ((CountSoFar + 1) * CharSize > *Size){\r
+      *Size = (CountSoFar + 1) * CharSize;\r
+      if (!Truncate) {\r
+        gEfiShellProtocol->SetFilePosition(Handle, OriginalFilePosition);\r
+      } else {\r
+        DEBUG((DEBUG_WARN, "The line was truncated in ShellFileHandleReadLine"));\r
+      }\r
+      return (EFI_BUFFER_TOO_SMALL);\r
+    }\r
+\r
+    if (*Ascii) {\r
+      if (CountSoFar && ((CHAR8*)Buffer)[CountSoFar - 1] == '\r') {\r
+        ((CHAR8*)Buffer)[CountSoFar - 1] = '\0';\r
+      }\r
+    }\r
+    else {\r
+      if (CountSoFar && Buffer[CountSoFar - 1] == L'\r') {\r
+        Buffer[CountSoFar - 1] = CHAR_NULL;\r
+      }\r
     }\r
-    return (EFI_BUFFER_TOO_SMALL);\r
-  }\r
-  while(Buffer[StrLen(Buffer)-1] == L'\r') {\r
-    Buffer[StrLen(Buffer)-1] = CHAR_NULL;\r
   }\r
 \r
   return (Status);\r