]> git.proxmox.com Git - mirror_edk2.git/blobdiff - ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c
This patch replaces StrCpy with StrnCpy or refactors out the usage of StrCpy through...
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Rm.c
index bde710faf044f9be2a4b1df3728f71c2c581e24c..6cc5dcf69107a91a6ea98f0b6aa56a5fa5f4cf81 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   Main file for attrib shell level 2 function.\r
 \r
-  Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>\r
+  Copyright (c) 2009 - 2014, 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
@@ -19,23 +19,31 @@ STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
   {NULL, TypeMax}\r
   };\r
 \r
+/**\r
+  Determine if a directory has no files in it.\r
+\r
+  @param[in] FileHandle   The EFI_HANDLE to the directory.\r
+  \r
+  @retval TRUE  The directory has no files (or directories).\r
+  @retval FALSE The directory has at least 1 file or directory in it.\r
+**/\r
 BOOLEAN\r
 EFIAPI\r
 IsDirectoryEmpty (\r
   IN EFI_HANDLE   FileHandle\r
   )\r
 {\r
-  EFI_STATUS      Status;\r
   EFI_FILE_INFO   *FileInfo;\r
   BOOLEAN         NoFile;\r
   BOOLEAN         RetVal;\r
 \r
   RetVal = TRUE;\r
   NoFile = FALSE;\r
+  FileInfo = NULL;\r
 \r
-  for (Status = FileHandleFindFirstFile(FileHandle, &FileInfo)\r
+  for (FileHandleFindFirstFile(FileHandle, &FileInfo)\r
     ;  !NoFile\r
-    ;  Status = FileHandleFindNextFile(FileHandle, FileInfo, &NoFile)\r
+    ;  FileHandleFindNextFile(FileHandle, FileInfo, &NoFile)\r
    ){\r
     if (StrStr(FileInfo->FileName, L".") != FileInfo->FileName\r
       &&StrStr(FileInfo->FileName, L"..") != FileInfo->FileName) {\r
@@ -45,6 +53,17 @@ IsDirectoryEmpty (
   return (RetVal);\r
 }\r
 \r
+/**\r
+  Delete a node and all nodes under it (including sub directories).\r
+\r
+  @param[in] Node   The node to start deleting with.\r
+  @param[in] Quiet  TRUE to print no messages.\r
+\r
+  @retval SHELL_SUCCESS       The operation was successful.\r
+  @retval SHELL_ACCESS_DENIED A file was read only.\r
+  @retval SHELL_ABORTED       The abort message was received.\r
+  @retval SHELL_DEVICE_ERROR  A device error occured reading this Node.\r
+**/\r
 SHELL_STATUS\r
 EFIAPI\r
 CascadeDelete(\r
@@ -57,6 +76,8 @@ CascadeDelete(
   EFI_SHELL_FILE_INFO   *Node2;\r
   EFI_STATUS            Status;\r
   SHELL_PROMPT_RESPONSE *Resp;\r
+  CHAR16                *TempName;\r
+  UINTN                 NewSize;\r
 \r
   Resp                  = NULL;\r
   ShellStatus           = SHELL_SUCCESS;\r
@@ -73,7 +94,6 @@ CascadeDelete(
       if (!Quiet) {\r
         Status = ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_RM_LOG_DELETE_CONF), gShellLevel2HiiHandle, Node->FullName);\r
         Status = ShellPromptForResponse(ShellPromptResponseTypeYesNo, NULL, (VOID**)&Resp);\r
-        ASSERT_EFI_ERROR(Status);\r
         ASSERT(Resp != NULL);\r
         if (EFI_ERROR(Status) || *Resp != ShellPromptResponseYes) {\r
           SHELL_FREE_NON_NULL(Resp);\r
@@ -102,7 +122,32 @@ CascadeDelete(
           continue;\r
         }\r
         Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE);\r
-        ShellStatus = CascadeDelete(Node2, Quiet);\r
+        if (EFI_ERROR(Node2->Status) && StrStr(Node2->FileName, L":") == NULL) {\r
+          //\r
+          // Update the node filename to have full path with file system identifier\r
+          //\r
+          NewSize = StrSize(Node->FullName) + StrSize(Node2->FullName);\r
+          TempName = AllocateZeroPool(NewSize);\r
+          if (TempName == NULL) {\r
+            ShellStatus = SHELL_OUT_OF_RESOURCES;\r
+          } else {\r
+            StrnCpy(TempName, Node->FullName, NewSize/sizeof(CHAR16) -1);\r
+            TempName[StrStr(TempName, L":")+1-TempName] = CHAR_NULL;\r
+            StrnCat(TempName, Node2->FullName, NewSize/sizeof(CHAR16) -1 - StrLen(TempName));\r
+            FreePool((VOID*)Node2->FullName);\r
+            Node2->FullName = TempName;\r
+\r
+            //\r
+            // Now try again to open the file\r
+            //\r
+            Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE);\r
+          }\r
+        }\r
+        if (!EFI_ERROR(Node2->Status)) {\r
+          ShellStatus = CascadeDelete(Node2, Quiet);\r
+        } else if (ShellStatus == SHELL_SUCCESS) {\r
+          ShellStatus = (SHELL_STATUS)(Node2->Status&(~0x80000000));\r
+        }\r
         if (ShellStatus != SHELL_SUCCESS) {\r
           if (List!=NULL) {\r
             gEfiShellProtocol->FreeFileList(&List);\r
@@ -126,17 +171,26 @@ CascadeDelete(
   }\r
 \r
   //\r
-  // We cant allow for the warning here!\r
+  // We cant allow for the warning here! (Dont use EFI_ERROR Macro).\r
   //\r
   if (Status != EFI_SUCCESS){\r
     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR), gShellLevel2HiiHandle, Status);\r
     return (SHELL_ACCESS_DENIED);\r
   } else {\r
-    ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_COMP), gShellLevel2HiiHandle);\r
+    if (!Quiet) {\r
+      ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_COMP), gShellLevel2HiiHandle);\r
+    }\r
     return (SHELL_SUCCESS);\r
   }\r
 }\r
 \r
+/**\r
+  Determins if a Node is a valid delete target.  Will prevent deleting the root directory.\r
+\r
+  @param[in] List       RESERVED.  Not used.\r
+  @param[in] Node       The node to analyze.\r
+  @param[in] Package    RESERVED.  Not used.\r
+**/\r
 BOOLEAN\r
 EFIAPI\r
 IsValidDeleteTarget(\r
@@ -146,27 +200,54 @@ IsValidDeleteTarget(
   )\r
 {\r
   CONST CHAR16        *TempLocation;\r
-  CHAR16              *Temp2;\r
+  BOOLEAN             RetVal;\r
+  CHAR16              *SearchString;\r
+  CHAR16              *Pattern;\r
   UINTN               Size;\r
 \r
+  if (Node == NULL || Node->FullName == NULL) {\r
+    return (FALSE);\r
+  }\r
+\r
   TempLocation = StrStr(Node->FullName, L":");\r
-  if (StrLen(TempLocation) == 2) {\r
+  if (StrLen(TempLocation) <= 2) {\r
     //\r
     // Deleting the root directory is invalid.\r
     //\r
     return (FALSE);\r
   }\r
+\r
   TempLocation = ShellGetCurrentDir(NULL);\r
-  Size = 0;\r
-  Temp2 = NULL;\r
-  StrnCatGrow(&Temp2, &Size, TempLocation, 0);\r
-  if (StrStr(Temp2, Node->FullName) != NULL) {\r
-    FreePool(Temp2);\r
-    return (FALSE);\r
+  if (TempLocation == NULL) {\r
+    //\r
+    // No working directory is specified so whatever is left is ok.\r
+    //\r
+    return (TRUE);\r
+  }\r
+\r
+  Pattern       = NULL;\r
+  SearchString  = NULL;\r
+  Size          = 0;\r
+  Pattern       = StrnCatGrow(&Pattern     , NULL, TempLocation  , 0);\r
+  SearchString  = StrnCatGrow(&SearchString, &Size, Node->FullName, 0);\r
+  if (!EFI_ERROR(ShellIsDirectory(SearchString))) {\r
+    SearchString  = StrnCatGrow(&SearchString, &Size, L"\\", 0);\r
+    SearchString  = StrnCatGrow(&SearchString, &Size, L"*", 0);\r
+  }\r
+\r
+  if (Pattern == NULL || SearchString == NULL) {\r
+    RetVal = FALSE;\r
+  } else {\r
+    RetVal = TRUE;\r
+    if (gUnicodeCollation->MetaiMatch(gUnicodeCollation, Pattern, SearchString)) {\r
+      RetVal = FALSE;\r
+    }\r
   }\r
-  FreePool(Temp2);\r
 \r
-  return (TRUE);\r
+  SHELL_FREE_NON_NULL(Pattern     );\r
+  SHELL_FREE_NON_NULL(SearchString);\r
+\r
+  return (RetVal);\r
 }\r
 \r
 /**\r