]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
ShellPkg: Update "ls" command to better handle "-r" parameter
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Ls.c
index fa588ff7f462fe167d2934c863b632bc8aeda5d3..b5ef6aa2a9fbce870ad8a24ade61bf7121f50a14 100644 (file)
@@ -330,8 +330,9 @@ PrintNonSfoFooter(
   @param[in] Attribs        List of required Attribute for display.\r
                             If 0 then all non-system and non-hidden files will be printed.\r
   @param[in] Sfo            TRUE to use Standard Format Output, FALSE otherwise\r
-  @param[in] Path           String with starting path.\r
-  @param[in] First          TRUE for the original and FALSE for any recursion spawned instances.\r
+  @param[in] RootPath       String with starting path to search in.\r
+  @param[in] SearchString   String with search string.\r
+  @param[in] Found          Set to TRUE, if anyone were found.\r
   @param[in] Count          The count of bits enabled in Attribs.\r
   @param[in] TimeZone       The current time zone offset.\r
 \r
@@ -343,8 +344,9 @@ PrintLsOutput(
   IN CONST BOOLEAN Rec,\r
   IN CONST UINT64  Attribs,\r
   IN CONST BOOLEAN Sfo,\r
-  IN CONST CHAR16  *Path,\r
-  IN CONST BOOLEAN First,\r
+  IN CONST CHAR16  *RootPath,\r
+  IN CONST CHAR16  *SearchString,\r
+  IN       BOOLEAN *Found,\r
   IN CONST UINTN   Count,\r
   IN CONST INT16   TimeZone\r
   )\r
@@ -356,10 +358,12 @@ PrintLsOutput(
   UINT64                FileCount;\r
   UINT64                DirCount;\r
   UINT64                FileSize;\r
-  CHAR16                *DirectoryName;\r
   UINTN                 LongestPath;\r
   CHAR16                *CorrectedPath;\r
+  BOOLEAN               FoundOne;\r
+  BOOLEAN               HeaderPrinted;\r
 \r
+  HeaderPrinted = FALSE;\r
   FileCount     = 0;\r
   DirCount      = 0;\r
   FileSize      = 0;\r
@@ -368,87 +372,96 @@ PrintLsOutput(
   LongestPath   = 0;\r
   CorrectedPath = NULL;\r
 \r
-  CorrectedPath = StrnCatGrow(&CorrectedPath, NULL, Path, 0);\r
+  if (Found != NULL) {\r
+    FoundOne = *Found;\r
+  } else {\r
+    FoundOne = FALSE;\r
+  }\r
+\r
+  CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath,     0);\r
+  if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'\r
+    &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {\r
+    CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\",     0);\r
+  }\r
+  CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0);\r
   if (CorrectedPath == NULL) {\r
     return (SHELL_OUT_OF_RESOURCES);\r
   }\r
 \r
   PathCleanUpDirectories(CorrectedPath);\r
 \r
-  if (!Sfo) {\r
-    PrintNonSfoHeader(CorrectedPath);\r
-  }\r
-\r
   Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);\r
-  if (EFI_ERROR(Status)) {\r
-    SHELL_FREE_NON_NULL(CorrectedPath);\r
-    if(Status == EFI_NOT_FOUND){\r
-      return (SHELL_NOT_FOUND);\r
+  if (!EFI_ERROR(Status)) {\r
+    if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {\r
+      SHELL_FREE_NON_NULL(CorrectedPath);\r
+      return (SHELL_SUCCESS);\r
     }\r
-    return (SHELL_DEVICE_ERROR);\r
-  }\r
-  if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {\r
-    SHELL_FREE_NON_NULL(CorrectedPath);\r
-    //\r
-    // On the first one only we expect to find something...\r
-    // do we find the . and .. directories otherwise?\r
-    //\r
-    if (First) {\r
-      return (SHELL_NOT_FOUND);\r
-    }\r
-    return (SHELL_SUCCESS);\r
-  }\r
 \r
-  if (Sfo && First) {\r
-    PrintSfoVolumeInfoTableEntry(ListHead);\r
-  }\r
-\r
-  for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)\r
-      ; !IsNull(&ListHead->Link, &Node->Link)\r
-      ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)\r
-      ){\r
-    ASSERT(Node != NULL);\r
-    if (LongestPath < StrSize(Node->FullName)) {\r
-      LongestPath = StrSize(Node->FullName);\r
+    if (Sfo && Found == NULL) {\r
+      PrintSfoVolumeInfoTableEntry(ListHead);\r
     }\r
-    ASSERT(Node->Info != NULL);\r
-    ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);\r
-    if (Attribs == 0) {\r
-      //\r
-      // NOT system & NOT hidden\r
-      //\r
-      if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)\r
-        || (Node->Info->Attribute & EFI_FILE_HIDDEN)\r
-       ){\r
-        continue;\r
+\r
+    for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0\r
+        ; !IsNull(&ListHead->Link, &Node->Link)\r
+        ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)\r
+        ){\r
+      ASSERT(Node != NULL);\r
+      if (LongestPath < StrSize(Node->FullName)) {\r
+        LongestPath = StrSize(Node->FullName);\r
       }\r
-    } else if ((Attribs != EFI_FILE_VALID_ATTR) ||\r
-               (Count == 5)) {\r
-      //\r
-      // Only matches the bits which "Attribs" contains, not\r
-      // all files/directories with any of the bits.\r
-      // Count == 5 is used to tell the difference between a user\r
-      // specifying all bits (EX: -arhsda) and just specifying\r
-      // -a (means display all files with any attribute).\r
-      //\r
-      if ( (Node->Info->Attribute & Attribs) != Attribs) {\r
-        continue;\r
+      ASSERT(Node->Info != NULL);\r
+      ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);\r
+      if (Attribs == 0) {\r
+        //\r
+        // NOT system & NOT hidden\r
+        //\r
+        if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)\r
+          || (Node->Info->Attribute & EFI_FILE_HIDDEN)\r
+         ){\r
+          continue;\r
+        }\r
+      } else if ((Attribs != EFI_FILE_VALID_ATTR) ||\r
+                 (Count == 5)) {\r
+        //\r
+        // Only matches the bits which "Attribs" contains, not\r
+        // all files/directories with any of the bits.\r
+        // Count == 5 is used to tell the difference between a user\r
+        // specifying all bits (EX: -arhsda) and just specifying\r
+        // -a (means display all files with any attribute).\r
+        //\r
+        if ( (Node->Info->Attribute & Attribs) != Attribs) {\r
+          continue;\r
+        }\r
       }\r
-    }\r
 \r
-    PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);\r
-  }\r
+      if (!Sfo && HeaderPrinted == FALSE) {\r
+        PrintNonSfoHeader(CorrectedPath);\r
+      }\r
+      PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);\r
+      FoundOne = TRUE;\r
+      HeaderPrinted = TRUE;\r
+    }\r
 \r
-  if (!Sfo) {\r
-    PrintNonSfoFooter(FileCount, FileSize, DirCount);\r
+    if (!Sfo) {\r
+      PrintNonSfoFooter(FileCount, FileSize, DirCount);\r
+    }\r
   }\r
 \r
-  if (Rec){\r
-    DirectoryName = AllocateZeroPool(LongestPath + 2*sizeof(CHAR16));\r
-    if (DirectoryName == NULL) {\r
-      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);\r
-      ShellStatus = SHELL_OUT_OF_RESOURCES;\r
-    } else {\r
+  if (Rec) {\r
+    //\r
+    // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter\r
+    //\r
+    ShellCloseFileMetaArg(&ListHead);\r
+    CorrectedPath[0] = CHAR_NULL;\r
+    CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);\r
+    if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'\r
+      &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {\r
+      CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\",     0);\r
+    }\r
+    CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*",     0);\r
+    Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);\r
+   \r
+    if (!EFI_ERROR(Status)) {\r
       for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)\r
           ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS\r
           ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)\r
@@ -465,24 +478,31 @@ PrintLsOutput(
           && StrCmp(Node->FileName, L".") != 0\r
           && StrCmp(Node->FileName, L"..") != 0\r
          ){\r
-          StrCpy(DirectoryName, Node->FullName);\r
-          StrCat(DirectoryName, L"\\*");\r
           ShellStatus = PrintLsOutput(\r
             Rec,\r
             Attribs,\r
             Sfo,\r
-            DirectoryName,\r
-            FALSE,\r
+            Node->FullName,\r
+            SearchString,\r
+            &FoundOne,\r
             Count,\r
             TimeZone);\r
         }\r
       }\r
-      FreePool(DirectoryName);\r
     }\r
   }\r
 \r
-  FreePool(CorrectedPath);\r
+  SHELL_FREE_NON_NULL(CorrectedPath);\r
   ShellCloseFileMetaArg(&ListHead);\r
+\r
+  if (Found == NULL && FoundOne == FALSE) {\r
+    return (SHELL_NOT_FOUND);\r
+  }\r
+\r
+  if (Found != NULL) {\r
+    *Found = FoundOne;\r
+  }\r
+\r
   return (ShellStatus);\r
 }\r
 \r
@@ -518,7 +538,7 @@ ShellCommandRunLs (
   CHAR16        *FullPath;\r
   UINTN         Size;\r
   EFI_TIME      TheTime;\r
-  BOOLEAN       SfoMode;\r
+  CHAR16        *SearchString;\r
 \r
   Size                = 0;\r
   FullPath            = NULL;\r
@@ -527,6 +547,7 @@ ShellCommandRunLs (
   ShellStatus         = SHELL_SUCCESS;\r
   RequiredAttributes  = 0;\r
   PathName            = NULL;\r
+  SearchString        = NULL;\r
   CurDir              = NULL;\r
   Count               = 0;\r
 \r
@@ -616,40 +637,52 @@ ShellCommandRunLs (
       if (ShellStatus == SHELL_SUCCESS) {\r
         PathName = ShellCommandLineGetRawValue(Package, 1);\r
         if (PathName == NULL) {\r
+          //\r
+          // Nothing specified... must start from current directory\r
+          //\r
           CurDir = gEfiShellProtocol->GetCurDir(NULL);\r
           if (CurDir == NULL) {\r
             ShellStatus = SHELL_NOT_FOUND;\r
             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
           }\r
-        }\r
-        if (PathName != NULL) {\r
+          //\r
+          // Copy to the 2 strings for starting path and file search string\r
+          //\r
+          ASSERT(SearchString == NULL);\r
+          ASSERT(FullPath == NULL);\r
+          StrnCatGrow(&SearchString, NULL, L"*", 0);\r
+          StrnCatGrow(&FullPath, NULL, CurDir, 0);\r
+        } else {\r
           if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {\r
+            //\r
+            // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.\r
+            //\r
             ShellStatus = SHELL_NOT_FOUND;\r
             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);\r
           } else {\r
+            //\r
+            // We got a valid fully qualified path or we have a CWD\r
+            //\r
             ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));\r
+            if (StrStr(PathName, L":") == NULL) {\r
+              StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);\r
+            }\r
             StrnCatGrow(&FullPath, &Size, PathName, 0);\r
             if  (ShellIsDirectory(PathName) == EFI_SUCCESS) {\r
-              if (PathName[StrLen (PathName) - 1] == '\\') {\r
-                //\r
-                // For path ending with '\', just append '*'.\r
-                //\r
-                StrnCatGrow (&FullPath, &Size, L"*", 0);\r
-              } else if (PathName[StrLen (PathName) - 1] == '*') {\r
-                //\r
-                // For path ending with '*', do nothing.\r
-                //\r
-              } else {\r
-                //\r
-                // Otherwise, append '\*' to directory name.\r
-                //\r
-                StrnCatGrow (&FullPath, &Size, L"\\*", 0);\r
-              }\r
+              //\r
+              // is listing ends with a directory, then we list all files in that directory\r
+              //\r
+              StrnCatGrow(&SearchString, NULL, L"*", 0);\r
+            } else {\r
+              //\r
+              // must split off the search part that applies to files from the end of the directory part\r
+              //\r
+              for (StrnCatGrow(&SearchString, NULL, PathName, 0)\r
+                ; SearchString != NULL && StrStr(SearchString, L"\\") != NULL\r
+                ; CopyMem(SearchString, StrStr(SearchString, L"\\") + 1, 1 + StrSize(StrStr(SearchString, L"\\") + 1))) ;\r
+              FullPath[StrLen(FullPath) - StrLen(SearchString)] = CHAR_NULL;\r
             }\r
           }\r
-        } else {\r
-          ASSERT(FullPath == NULL);\r
-          StrnCatGrow(&FullPath, NULL, L"*", 0);\r
         }\r
         Status = gRT->GetTime(&TheTime, NULL);\r
         if (EFI_ERROR(Status)) {\r
@@ -657,14 +690,14 @@ ShellCommandRunLs (
           TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
         }\r
 \r
-        SfoMode = ShellCommandLineGetFlag(Package, L"-sfo");\r
         if (ShellStatus == SHELL_SUCCESS) {\r
           ShellStatus = PrintLsOutput(\r
             ShellCommandLineGetFlag(Package, L"-r"),\r
             RequiredAttributes,\r
-            SfoMode,\r
+            ShellCommandLineGetFlag(Package, L"-sfo"),\r
             FullPath,\r
-            TRUE,\r
+            SearchString,\r
+            NULL,\r
             Count,\r
             (INT16)(TheTime.TimeZone==EFI_UNSPECIFIED_TIMEZONE?0:TheTime.TimeZone)\r
            );\r
@@ -684,12 +717,11 @@ ShellCommandRunLs (
     }\r
   }\r
 \r
-  if (FullPath != NULL) {\r
-    FreePool(FullPath);\r
-  }\r
   //\r
-  // free the command line package\r
+  // Free memory allocated\r
   //\r
+  SHELL_FREE_NON_NULL(SearchString);\r
+  SHELL_FREE_NON_NULL(FullPath);\r
   ShellCommandLineFreeVarList (Package);\r
 \r
   return (ShellStatus);\r