public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ruiyu Ni <ruiyu.ni@intel.com>
To: edk2-devel@lists.01.org
Cc: Chen A Chen <chen.a.chen@intel.com>,
	Jaben Carsey <jaben.carsey@intel.com>
Subject: [PATCH 2/2] ShellPkg/cd: Fix "cd" to support "fs0:dir" (no slash after ':')
Date: Wed, 21 Dec 2016 16:55:01 +0800	[thread overview]
Message-ID: <20161221085501.159796-3-ruiyu.ni@intel.com> (raw)
In-Reply-To: <20161221085501.159796-1-ruiyu.ni@intel.com>

When "fs0:dir"(drive letter without slash) is used as destination
of "cd", "cd" tries to change to "dir" in root directory of "fs0:".
It's incorrect. The correct behavior is to change to "dir" in
current directory of "fs0:"

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com>
Signed-off-by: Chen A Chen <chen.a.chen@intel.com>
Cc: Jaben Carsey <jaben.carsey@intel.com>
---
 ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c | 415 +++++++++++++----------
 1 file changed, 240 insertions(+), 175 deletions(-)

diff --git a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c
index 0967bc7..0b4becf 100644
--- a/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c
+++ b/ShellPkg/Library/UefiShellLevel2CommandsLib/Cd.c
@@ -17,6 +17,156 @@
 #include "UefiShellLevel2CommandsLib.h"
 
 /**
+  Function will replace drive identifier with CWD.
+
+  If FullPath begining with ':' is invalid path, then ASSERT.
+  If FullPath not include dirve identifier , then do nothing.
+  If FullPath likes "fs0:\xx" or "fs0:/xx" , then do nothing.
+  If FullPath likes "fs0:xxx" or "fs0:", the drive replaced by CWD.
+
+  @param[in, out]   FullPath    The pointer to the string containing the path.
+  @param[in]        Cwd         Current directory.
+
+  @retval   EFI_SUCCESS         Success.
+  @retval   EFI_OUT_OF_SOURCES  A memory allocation failed.
+**/
+EFI_STATUS
+ReplaceDriveWithCwd(
+  IN OUT    CHAR16  **FullPath,
+  IN CONST  CHAR16  *Cwd
+  )
+{
+  CHAR16        *Splitter;
+  CHAR16        *TempBuffer;
+  UINTN         TotalSize;
+
+  Splitter   = NULL;
+  TempBuffer = NULL;
+  TotalSize  = 0;
+
+  if (FullPath == NULL || *FullPath == NULL) {
+    return EFI_SUCCESS;
+  }
+
+  Splitter = StrStr (*FullPath, L":");
+  ASSERT(Splitter != *FullPath);
+
+  if (Splitter != NULL && *(Splitter + 1) != L'\\' && *(Splitter + 1) != L'/') {
+    TotalSize = StrSize (Cwd) + StrSize (Splitter + 1);
+    TempBuffer = AllocateZeroPool (TotalSize);
+    if (TempBuffer == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    StrCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd);
+    StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), L"\\");
+    StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Splitter + 1);
+
+    FreePool(*FullPath);
+    *FullPath = TempBuffer;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  function to determine if FullPath is under current filesystem.
+
+  @param[in]    FullPath    The target location to determine.
+  @param[in]    Cwd         Current directory.
+
+  @retval       TRUE        The FullPath is in the current filesystem.
+  @retval       FALSE       The FullPaht isn't in the current filesystem.
+**/
+BOOLEAN
+IsCurrentFileSystem(
+  IN CONST CHAR16   *FullPath,
+  IN CONST CHAR16   *Cwd
+  )
+{
+  CHAR16 *Splitter1;
+  CHAR16 *Splitter2;
+
+  Splitter1 = NULL;
+  Splitter2 = NULL;
+
+  ASSERT(FullPath != NULL);
+
+  Splitter1 = StrStr (FullPath, L":");
+  if (Splitter1 == NULL) {
+    return TRUE;
+  }
+
+  Splitter2 = StrStr (Cwd, L":");
+
+  if ((UINTN)(Splitter1 - FullPath) != (UINTN)(Splitter2 - Cwd)) {
+    return FALSE;
+  } else {
+    if (StrniCmp(FullPath, Cwd, (UINTN)(Splitter1 - FullPath)) == NULL) {
+      return TRUE;
+    } else {
+      return FALSE;
+    }
+  }
+}
+
+/**
+  Extract drive string and path string from FullPath.
+
+  The caller must be free Drive and Path.
+
+  @param[in]    FullPath    A path to be extracted.
+  @param[out]   Drive       Buffer to save drive identifier.
+  @param[out]   Path        Buffer to save path.
+
+  @retval       EFI_SUCCESS           Success.
+  @retval       EFI_OUT_OF_RESOUCES   A memory allocation failed.
+**/
+EFI_STATUS
+ExtractDriveAndPath(
+  IN CONST CHAR16   *FullPath,
+  OUT CHAR16        **Drive,
+  OUT CHAR16        **Path
+  )
+{
+  CHAR16 *Splitter;
+
+  ASSERT(FullPath != NULL);
+
+  Splitter = StrStr (FullPath, L":");
+
+  if (Splitter == NULL) {
+    *Drive = NULL;
+    *Path = AllocateCopyPool (StrSize (FullPath), FullPath);
+    if (*Path == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+  } else {
+    if (*(Splitter + 1) == CHAR_NULL) {
+      *Drive = AllocateCopyPool (StrSize (FullPath), FullPath);
+      *Path = NULL;
+      if (*Drive == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+    } else {
+      *Drive = AllocateCopyPool((Splitter - FullPath + 2) * sizeof(CHAR16), FullPath);
+      if (*Drive == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      (*Drive)[Splitter - FullPath + 1] = CHAR_NULL;
+
+      *Path = AllocateCopyPool (StrSize (Splitter + 1), Splitter + 1);
+      if (*Path == NULL) {
+        FreePool(*Drive);
+        return EFI_OUT_OF_RESOURCES;
+      }
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
   Function for 'cd' command.
 
   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
@@ -31,23 +181,26 @@ ShellCommandRunCd (
 {
   EFI_STATUS        Status;
   LIST_ENTRY        *Package;
-  CONST CHAR16      *Directory;
-  CHAR16            *Cwd;
+  CONST CHAR16      *Cwd;
   CHAR16            *Path;
   CHAR16            *Drive;
-  UINTN             CwdSize;
-  UINTN             DriveSize;
   CHAR16            *ProblemParam;
   SHELL_STATUS      ShellStatus;
-  SHELL_FILE_HANDLE Handle;
   CONST CHAR16      *Param1;
   CHAR16            *Param1Copy;
-  CHAR16*           Walker;
+  CHAR16            *Walker;
+  CHAR16            *Splitter;
+  CHAR16            *TempBuffer;
+  UINTN             TotalSize;
 
-  ProblemParam = NULL;
-  ShellStatus = SHELL_SUCCESS;
-  Drive = NULL;
-  DriveSize = 0;
+  ProblemParam  = NULL;
+  ShellStatus   = SHELL_SUCCESS;
+  Cwd           = NULL;
+  Path          = NULL;
+  Drive         = NULL;
+  Splitter      = NULL;
+  TempBuffer    = NULL;
+  TotalSize     = 0;
 
   Status = CommandInit();
   ASSERT_EFI_ERROR(Status);
@@ -87,194 +240,106 @@ ShellCommandRunCd (
     // else If there are 2 value parameters, then print the error message
     // else If there is  1 value paramerer , then change the directory
     //
-    Param1 = ShellCommandLineGetRawValue(Package, 1);
-    if (Param1 == NULL) {
-      //
-      // display the current directory
-      //
-      Directory = ShellGetCurrentDir(NULL);
-      if (Directory != NULL) {
-        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_PRINT), gShellLevel2HiiHandle, Directory);
-      } else {
-        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");  
-        ShellStatus = SHELL_NOT_FOUND;
-      }
+    Cwd = ShellGetCurrentDir (NULL);
+    if (Cwd == NULL) {
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");
+      ShellStatus = SHELL_NOT_FOUND;
     } else {
-      Param1Copy = CatSPrint(NULL, L"%s", Param1, NULL);
-      for (Walker = Param1Copy; Walker != NULL && *Walker != CHAR_NULL ; Walker++) {
-        if (*Walker == L'\"') {
-          CopyMem(Walker, Walker+1, StrSize(Walker) - sizeof(Walker[0]));
+      Param1 = ShellCommandLineGetRawValue(Package, 1);
+      if (Param1 == NULL) {
+        //
+        // display the current directory
+        //
+        ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_CD_PRINT), gShellLevel2HiiHandle, Cwd);
+      } else {
+        Param1Copy = CatSPrint(NULL, L"%s", Param1, NULL);
+        for (Walker = Param1Copy; Walker != NULL && *Walker != CHAR_NULL; Walker++) {
+          if (*Walker == L'\"') {
+            CopyMem(Walker, Walker + 1, StrSize(Walker) - sizeof(Walker[0]));
+          }
         }
-      }
-      
-      if (Param1Copy != NULL) {
-        Param1Copy = PathCleanUpDirectories(Param1Copy);
-      }
-      if (Param1Copy != NULL) {
-        if (StrCmp(Param1Copy, L".") == 0) {
-          //
-          // nothing to do... change to current directory
-          //
-        } else if (StrCmp(Param1Copy, L"..") == 0) {
+
+        if (Param1Copy != NULL && IsCurrentFileSystem (Param1Copy, Cwd)) {
+          Status = ReplaceDriveWithCwd (&Param1Copy,Cwd);
+          if (!EFI_ERROR(Status)) {
+            Param1Copy = PathCleanUpDirectories(Param1Copy);
+          }
+        } else {
           //
-          // Change up one directory...
+          // Can't use cd command to change filesystem.
           //
-          Directory = ShellGetCurrentDir(NULL);
-          if (Directory == NULL) {
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");  
-            ShellStatus = SHELL_NOT_FOUND;
-          } else {
-            CwdSize = StrSize(Directory) + sizeof(CHAR16);
-            Cwd = AllocateZeroPool(CwdSize);
-            if (Cwd == NULL) {
-              ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cd");
-              ShellStatus = SHELL_OUT_OF_RESOURCES;
-            } else {
-              StrCpyS (Cwd, StrSize (Directory) / sizeof (CHAR16) + 1, Directory);
-              StrCatS (Cwd, StrSize (Directory) / sizeof (CHAR16) + 1, L"\\");
-              Drive = GetFullyQualifiedPath (Cwd);
-              PathRemoveLastItem (Drive);
-              FreePool (Cwd);
-            }
-          }
-          if (ShellStatus == SHELL_SUCCESS && Drive != NULL) {
+          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");
+          Status = EFI_NOT_FOUND;
+        }
+
+        if (!EFI_ERROR(Status) && Param1Copy != NULL) {
+          Splitter = StrStr (Cwd, L":");
+          if (Param1Copy[0] == L'\\') {
             //
-            // change directory on current drive letter
+            // Absolute Path on current drive letter.
             //
-            Status = gEfiShellProtocol->SetCurDir(NULL, Drive);
-            if (Status == EFI_NOT_FOUND) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
-              ShellStatus = SHELL_NOT_FOUND;
+            TotalSize = ((Splitter - Cwd + 1) * sizeof(CHAR16)) + StrSize(Param1Copy);
+            TempBuffer = AllocateZeroPool(TotalSize);
+            if (TempBuffer == NULL) {
+              Status = EFI_OUT_OF_RESOURCES;
+            } else {
+              StrnCpyS(TempBuffer, TotalSize / sizeof(CHAR16), Cwd, (Splitter - Cwd + 1));
+              StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Param1Copy);
+
+              FreePool(Param1Copy);
+              Param1Copy = TempBuffer;
+              TempBuffer = NULL;
             }
-          }
-        } else if (StrCmp(Param1Copy, L"\\") == 0) {
-          //
-          // Move to root of current drive
-          //
-          Directory = ShellGetCurrentDir(NULL);
-          if (Directory == NULL) {
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");  
-            ShellStatus = SHELL_NOT_FOUND;
           } else {
-            CwdSize = StrSize(Directory) + sizeof(CHAR16);
-            Cwd = AllocateZeroPool(CwdSize);
-            if (Cwd == NULL) {
-              ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_OUT_MEM), gShellLevel2HiiHandle, L"cd");
-              ShellStatus = SHELL_OUT_OF_RESOURCES;
-            } else {
-              StrCpyS (Cwd, StrSize (Directory) / sizeof (CHAR16) + 1, Directory);
-              StrCatS (Cwd, StrSize (Directory) / sizeof (CHAR16) + 1, L"\\");
-              Drive = GetFullyQualifiedPath (Cwd);
-              while (PathRemoveLastItem (Drive)) {
-                //
-                // Check if Drive contains 'fsx:\' only or still points to a sub-directory.
-                // Don't remove trailing '\' from Drive if it points to the root directory.
-                //
-                Path = StrStr (Drive, L":\\");
-                if ((Path != NULL) && (*(Path + 2) == CHAR_NULL)) {
-                  break;
-                }
+            if (StrStr (Param1Copy,L":") == NULL) {
+              TotalSize = StrSize(Cwd) + StrSize (Param1Copy);
+              TempBuffer = AllocateZeroPool (TotalSize);
+              if (TempBuffer == NULL) {
+                Status = EFI_OUT_OF_RESOURCES;
+              } else {
+                StrCpyS (TempBuffer, TotalSize / sizeof(CHAR16), Cwd);
+                StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), L"\\");
+                StrCatS (TempBuffer, TotalSize / sizeof(CHAR16), Param1Copy);
+
+                FreePool(Param1Copy);
+                Param1Copy = PathCleanUpDirectories (TempBuffer);
               }
-              FreePool (Cwd);
             }
           }
-          if (ShellStatus == SHELL_SUCCESS && Drive != NULL) {
-            //
-            // change directory on current drive letter
-            //
-            Status = gEfiShellProtocol->SetCurDir(NULL, Drive);
-            if (Status == EFI_NOT_FOUND) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
-              ShellStatus = SHELL_NOT_FOUND;
-            }
-          }
-        } else if (StrStr(Param1Copy, L":") == NULL) {
-          //
-          // change directory without a drive identifier
-          //
-          if (ShellGetCurrentDir(NULL) == NULL) {
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cd");  
+        }
+
+        if (!EFI_ERROR(Status)) {
+          Status = ExtractDriveAndPath(Param1Copy, &Drive, &Path);
+        }
+
+        if (!EFI_ERROR(Status) && Drive != NULL && Path != NULL) {
+          if (EFI_ERROR(ShellIsDirectory(Param1Copy))) {
+            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Param1Copy);
             ShellStatus = SHELL_NOT_FOUND;
           } else {
-            ASSERT((Drive == NULL && DriveSize == 0) || (Drive != NULL));
-            Drive = StrnCatGrow(&Drive, &DriveSize, ShellGetCurrentDir(NULL), 0);
-            Drive = StrnCatGrow(&Drive, &DriveSize, L"\\", 0);
-            if (*Param1Copy == L'\\') {
-              while (PathRemoveLastItem(Drive)) ;
-              Drive = StrnCatGrow(&Drive, &DriveSize, Param1Copy+1, 0);
-            } else {
-              Drive = StrnCatGrow(&Drive, &DriveSize, Param1Copy, 0);
-            }
-            //
-            // Verify that this is a valid directory
-            //
-            Status = gEfiShellProtocol->OpenFileByName(Drive, &Handle, EFI_FILE_MODE_READ);
+            Status = gEfiShellProtocol->SetCurDir(Drive, Path + 1);
             if (EFI_ERROR(Status)) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Drive);  
-              ShellStatus = SHELL_NOT_FOUND;
-            } else if (EFI_ERROR(FileHandleIsDirectory(Handle))) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Drive);  
-              ShellStatus = SHELL_NOT_FOUND;
-            }
-            if (ShellStatus == SHELL_SUCCESS && Drive != NULL) {
-              //
-              // change directory on current drive letter
-              //
-              Status = gEfiShellProtocol->SetCurDir(NULL, Drive);
-              if (Status == EFI_NOT_FOUND) {
-                ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
-                ShellStatus = SHELL_NOT_FOUND;
-              }
-            }
-            if (Handle != NULL) {
-              gEfiShellProtocol->CloseFile(Handle);
-              DEBUG_CODE(Handle = NULL;);
-            }
-          }
-        } else {
-          //
-          // change directory with a drive letter
-          //
-          Drive = AllocateCopyPool(StrSize(Param1Copy), Param1Copy);
-          if (Drive == NULL) {
-            ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle, L"cd");  
-            ShellStatus = SHELL_OUT_OF_RESOURCES;
-          } else {
-            Path = StrStr(Drive, L":");
-            ASSERT(Path != NULL);
-            if (EFI_ERROR(ShellIsDirectory(Param1Copy))) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cd", Param1Copy);  
-              ShellStatus = SHELL_NOT_FOUND;
-            } else if (*(Path+1) == CHAR_NULL) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
+              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Param1Copy);
               ShellStatus = SHELL_NOT_FOUND;
             } else {
-              *(Path+1) = CHAR_NULL;
-              if (Path == Drive + StrLen(Drive)) {
-                ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
-                ShellStatus = SHELL_NOT_FOUND;
-              } else {
-                Status = gEfiShellProtocol->SetCurDir(Drive, Path+2);
-                ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_PRINT), gShellLevel2HiiHandle, ShellGetCurrentDir(Drive));
-              }
-            }
-            if (Status == EFI_NOT_FOUND) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CD_NF), gShellLevel2HiiHandle, L"cd");  
-              Status = SHELL_NOT_FOUND;
-            } else if (EFI_ERROR(Status)) {
-              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cd", Param1Copy);  
-              Status = SHELL_NOT_FOUND;
+              ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_CD_PRINT), gShellLevel2HiiHandle, ShellGetCurrentDir(Drive));
             }
           }
         }
+
+        if (Drive != NULL) {
+          FreePool (Drive);
+        }
+
+        if (Path != NULL) {
+          FreePool (Path);
+        }
+
+        FreePool(Param1Copy);
       }
-      FreePool(Param1Copy);
     }
   }
 
-  if (Drive != NULL) {
-    FreePool(Drive);
-  }
   //
   // free the command line package
   //
-- 
2.9.0.windows.1



  parent reply	other threads:[~2016-12-21  8:55 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-21  8:54 [PATCH 0/2] ShellPkg/cd: Fix "cd" to support "fs0:dir" (no slash after ':') Ruiyu Ni
2016-12-21  8:55 ` [PATCH 1/2] MdePkg/BaseLib: Fix PathCleanUpDirectories to correctly handle "\.\" Ruiyu Ni
2016-12-21  8:55 ` Ruiyu Ni [this message]
2016-12-21 16:23   ` [PATCH 2/2] ShellPkg/cd: Fix "cd" to support "fs0:dir" (no slash after ':') Carsey, Jaben
2016-12-23  5:43     ` Ni, Ruiyu
2016-12-27 23:01       ` Carsey, Jaben

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20161221085501.159796-3-ruiyu.ni@intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox