]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiShellLevel2CommandsLib/Rm.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Rm.c
CommitLineData
a405b86d 1/** @file\r
2 Main file for attrib shell level 2 function.\r
3\r
c011b6c9 4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
7506fe43 5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
56ba3746 6 SPDX-License-Identifier: BSD-2-Clause-Patent\r
a405b86d 7\r
8**/\r
9\r
10#include "UefiShellLevel2CommandsLib.h"\r
11\r
47d20b54
MK
12STATIC CONST SHELL_PARAM_ITEM ParamList[] = {\r
13 { L"-q", TypeFlag },\r
14 { NULL, TypeMax }\r
15};\r
a405b86d 16\r
b54fd049 17/**\r
18 Determine if a directory has no files in it.\r
19\r
20 @param[in] FileHandle The EFI_HANDLE to the directory.\r
ba0014b9 21\r
b54fd049 22 @retval TRUE The directory has no files (or directories).\r
23 @retval FALSE The directory has at least 1 file or directory in it.\r
24**/\r
a405b86d 25BOOLEAN\r
a405b86d 26IsDirectoryEmpty (\r
47d20b54 27 IN SHELL_FILE_HANDLE FileHandle\r
a405b86d 28 )\r
29{\r
47d20b54
MK
30 EFI_STATUS Status;\r
31 EFI_FILE_INFO *FileInfo;\r
32 BOOLEAN NoFile;\r
33 BOOLEAN RetVal;\r
a405b86d 34\r
47d20b54
MK
35 RetVal = TRUE;\r
36 NoFile = FALSE;\r
0d807dae 37 FileInfo = NULL;\r
a405b86d 38\r
47d20b54
MK
39 for (Status = FileHandleFindFirstFile (FileHandle, &FileInfo)\r
40 ; !NoFile && !EFI_ERROR (Status)\r
41 ; FileHandleFindNextFile (FileHandle, FileInfo, &NoFile)\r
42 )\r
43 {\r
44 if ( (StrStr (FileInfo->FileName, L".") != FileInfo->FileName)\r
45 && (StrStr (FileInfo->FileName, L"..") != FileInfo->FileName))\r
46 {\r
a405b86d 47 RetVal = FALSE;\r
48 }\r
49 }\r
47d20b54 50\r
a405b86d 51 return (RetVal);\r
52}\r
53\r
b54fd049 54/**\r
55 Delete a node and all nodes under it (including sub directories).\r
56\r
57 @param[in] Node The node to start deleting with.\r
58 @param[in] Quiet TRUE to print no messages.\r
59\r
60 @retval SHELL_SUCCESS The operation was successful.\r
61 @retval SHELL_ACCESS_DENIED A file was read only.\r
62 @retval SHELL_ABORTED The abort message was received.\r
a048af3c 63 @retval SHELL_DEVICE_ERROR A device error occurred reading this Node.\r
b54fd049 64**/\r
a405b86d 65SHELL_STATUS\r
47d20b54 66CascadeDelete (\r
a405b86d 67 IN EFI_SHELL_FILE_INFO *Node,\r
68 IN CONST BOOLEAN Quiet\r
69 )\r
70{\r
47d20b54
MK
71 SHELL_STATUS ShellStatus;\r
72 EFI_SHELL_FILE_INFO *List;\r
73 EFI_SHELL_FILE_INFO *Node2;\r
74 EFI_STATUS Status;\r
75 SHELL_PROMPT_RESPONSE *Resp;\r
76 CHAR16 *TempName;\r
77 UINTN NewSize;\r
78\r
79 Resp = NULL;\r
80 ShellStatus = SHELL_SUCCESS;\r
81 List = NULL;\r
82 Status = EFI_SUCCESS;\r
a405b86d 83\r
84 if ((Node->Info->Attribute & EFI_FILE_READ_ONLY) == EFI_FILE_READ_ONLY) {\r
47d20b54 85 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DETELE_RO), gShellLevel2HiiHandle, L"rm", Node->FullName);\r
a405b86d 86 return (SHELL_ACCESS_DENIED);\r
87 }\r
88\r
89 if ((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY) {\r
47d20b54 90 if (!IsDirectoryEmpty (Node->Handle)) {\r
a405b86d 91 if (!Quiet) {\r
47d20b54
MK
92 Status = ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_CONF), gShellLevel2HiiHandle, Node->FullName);\r
93 Status = ShellPromptForResponse (ShellPromptResponseTypeYesNo, NULL, (VOID **)&Resp);\r
94 ASSERT (Resp != NULL);\r
95 if (EFI_ERROR (Status) || (*Resp != ShellPromptResponseYes)) {\r
96 SHELL_FREE_NON_NULL (Resp);\r
a405b86d 97 return (SHELL_ABORTED);\r
98 }\r
47d20b54
MK
99\r
100 SHELL_FREE_NON_NULL (Resp);\r
a405b86d 101 }\r
47d20b54 102\r
a405b86d 103 //\r
104 // empty out the directory\r
105 //\r
47d20b54
MK
106 Status = gEfiShellProtocol->FindFilesInDir (Node->Handle, &List);\r
107 if (EFI_ERROR (Status)) {\r
108 if (List != NULL) {\r
109 gEfiShellProtocol->FreeFileList (&List);\r
a405b86d 110 }\r
47d20b54 111\r
a405b86d 112 return (SHELL_DEVICE_ERROR);\r
113 }\r
47d20b54
MK
114\r
115 for (Node2 = (EFI_SHELL_FILE_INFO *)GetFirstNode (&List->Link)\r
116 ; !IsNull (&List->Link, &Node2->Link)\r
117 ; Node2 = (EFI_SHELL_FILE_INFO *)GetNextNode (&List->Link, &Node2->Link)\r
118 )\r
119 {\r
a405b86d 120 //\r
121 // skip the directory traversing stuff...\r
122 //\r
47d20b54 123 if ((StrCmp (Node2->FileName, L".") == 0) || (StrCmp (Node2->FileName, L"..") == 0)) {\r
a405b86d 124 continue;\r
125 }\r
47d20b54 126\r
a405b86d 127 Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE);\r
47d20b54 128 if (EFI_ERROR (Node2->Status) && (StrStr (Node2->FileName, L":") == NULL)) {\r
22feb630
JC
129 //\r
130 // Update the node filename to have full path with file system identifier\r
131 //\r
47d20b54
MK
132 NewSize = StrSize (Node->FullName) + StrSize (Node2->FullName);\r
133 TempName = AllocateZeroPool (NewSize);\r
7461437c 134 if (TempName == NULL) {\r
73c5c619 135 ShellStatus = SHELL_OUT_OF_RESOURCES;\r
7461437c 136 } else {\r
47d20b54
MK
137 StrCpyS (TempName, NewSize/sizeof (CHAR16), Node->FullName);\r
138 TempName[StrStr (TempName, L":")+1-TempName] = CHAR_NULL;\r
139 StrCatS (TempName, NewSize/sizeof (CHAR16), Node2->FullName);\r
140 FreePool ((VOID *)Node2->FullName);\r
7461437c 141 Node2->FullName = TempName;\r
142\r
143 //\r
144 // Now try again to open the file\r
145 //\r
146 Node2->Status = gEfiShellProtocol->OpenFileByName (Node2->FullName, &Node2->Handle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE);\r
147 }\r
148 }\r
47d20b54
MK
149\r
150 if (!EFI_ERROR (Node2->Status)) {\r
151 ShellStatus = CascadeDelete (Node2, Quiet);\r
7461437c 152 } else if (ShellStatus == SHELL_SUCCESS) {\r
75a68c69 153 ShellStatus = (SHELL_STATUS)(Node2->Status&(~0x80000000));\r
22feb630 154 }\r
47d20b54 155\r
a405b86d 156 if (ShellStatus != SHELL_SUCCESS) {\r
47d20b54
MK
157 if (List != NULL) {\r
158 gEfiShellProtocol->FreeFileList (&List);\r
a405b86d 159 }\r
47d20b54 160\r
a405b86d 161 return (ShellStatus);\r
162 }\r
163 }\r
47d20b54
MK
164\r
165 if (List != NULL) {\r
166 gEfiShellProtocol->FreeFileList (&List);\r
a405b86d 167 }\r
168 }\r
169 }\r
170\r
47d20b54 171 if (!((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0))) {\r
a405b86d 172 //\r
173 // now delete the current node...\r
174 //\r
5a51ad8d 175 if (!Quiet) {\r
47d20b54 176 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE), gShellLevel2HiiHandle, Node->FullName);\r
5a51ad8d 177 }\r
47d20b54
MK
178\r
179 Status = gEfiShellProtocol->DeleteFile (Node->Handle);\r
a405b86d 180 Node->Handle = NULL;\r
181 }\r
182\r
183 //\r
b54fd049 184 // We cant allow for the warning here! (Dont use EFI_ERROR Macro).\r
a405b86d 185 //\r
47d20b54
MK
186 if (Status != EFI_SUCCESS) {\r
187 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR), gShellLevel2HiiHandle, Status);\r
a405b86d 188 return (SHELL_ACCESS_DENIED);\r
189 } else {\r
a737ea73 190 if (!Quiet) {\r
47d20b54 191 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_COMP), gShellLevel2HiiHandle);\r
a737ea73 192 }\r
47d20b54 193\r
a405b86d 194 return (SHELL_SUCCESS);\r
195 }\r
196}\r
197\r
b54fd049 198/**\r
cceb4ebd 199 Determines if a Node is a valid delete target. Will prevent deleting the root directory.\r
b54fd049 200\r
201 @param[in] List RESERVED. Not used.\r
202 @param[in] Node The node to analyze.\r
203 @param[in] Package RESERVED. Not used.\r
204**/\r
a405b86d 205BOOLEAN\r
47d20b54 206IsValidDeleteTarget (\r
a405b86d 207 IN CONST EFI_SHELL_FILE_INFO *List,\r
208 IN CONST EFI_SHELL_FILE_INFO *Node,\r
209 IN CONST LIST_ENTRY *Package\r
210 )\r
211{\r
47d20b54
MK
212 CONST CHAR16 *TempLocation;\r
213 BOOLEAN RetVal;\r
214 CHAR16 *SearchString;\r
215 CHAR16 *Pattern;\r
216 UINTN Size;\r
a405b86d 217\r
47d20b54 218 if ((Node == NULL) || (Node->FullName == NULL)) {\r
eef1ed46 219 return (FALSE);\r
220 }\r
221\r
47d20b54
MK
222 TempLocation = StrStr (Node->FullName, L":");\r
223 if (StrLen (TempLocation) <= 2) {\r
a405b86d 224 //\r
225 // Deleting the root directory is invalid.\r
226 //\r
227 return (FALSE);\r
228 }\r
eef1ed46 229\r
47d20b54 230 TempLocation = ShellGetCurrentDir (NULL);\r
eef1ed46 231 if (TempLocation == NULL) {\r
232 //\r
233 // No working directory is specified so whatever is left is ok.\r
234 //\r
235 return (TRUE);\r
a405b86d 236 }\r
a405b86d 237\r
47d20b54
MK
238 Pattern = NULL;\r
239 SearchString = NULL;\r
240 Size = 0;\r
241 Pattern = StrnCatGrow (&Pattern, &Size, TempLocation, 0);\r
242 Pattern = StrnCatGrow (&Pattern, &Size, L"\\", 0);\r
243 Size = 0;\r
244 SearchString = StrnCatGrow (&SearchString, &Size, Node->FullName, 0);\r
245 if (!EFI_ERROR (ShellIsDirectory (SearchString))) {\r
246 SearchString = StrnCatGrow (&SearchString, &Size, L"\\", 0);\r
247 SearchString = StrnCatGrow (&SearchString, &Size, L"*", 0);\r
a32980dd 248 }\r
eef1ed46 249\r
47d20b54 250 if ((Pattern == NULL) || (SearchString == NULL)) {\r
eef1ed46 251 RetVal = FALSE;\r
252 } else {\r
253 RetVal = TRUE;\r
47d20b54 254 if (gUnicodeCollation->MetaiMatch (gUnicodeCollation, Pattern, SearchString)) {\r
eef1ed46 255 RetVal = FALSE;\r
256 }\r
257 }\r
258\r
47d20b54
MK
259 SHELL_FREE_NON_NULL (Pattern);\r
260 SHELL_FREE_NON_NULL (SearchString);\r
eef1ed46 261\r
262 return (RetVal);\r
a405b86d 263}\r
264\r
265/**\r
266 Function for 'rm' command.\r
267\r
268 @param[in] ImageHandle Handle to the Image (NULL if Internal).\r
269 @param[in] SystemTable Pointer to the System Table (NULL if Internal).\r
270**/\r
271SHELL_STATUS\r
272EFIAPI\r
273ShellCommandRunRm (\r
274 IN EFI_HANDLE ImageHandle,\r
275 IN EFI_SYSTEM_TABLE *SystemTable\r
276 )\r
277{\r
47d20b54
MK
278 EFI_STATUS Status;\r
279 LIST_ENTRY *Package;\r
280 CHAR16 *ProblemParam;\r
281 CONST CHAR16 *Param;\r
282 SHELL_STATUS ShellStatus;\r
283 UINTN ParamCount;\r
284 EFI_SHELL_FILE_INFO *FileList;\r
285 EFI_SHELL_FILE_INFO *Node;\r
286\r
287 ProblemParam = NULL;\r
288 ShellStatus = SHELL_SUCCESS;\r
289 ParamCount = 0;\r
290 FileList = NULL;\r
a405b86d 291\r
292 //\r
293 // initialize the shell lib (we must be in non-auto-init...)\r
294 //\r
47d20b54
MK
295 Status = ShellInitialize ();\r
296 ASSERT_EFI_ERROR (Status);\r
a405b86d 297\r
298 //\r
299 // parse the command line\r
300 //\r
301 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);\r
47d20b54
MK
302 if (EFI_ERROR (Status)) {\r
303 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {\r
304 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"rm", ProblemParam);\r
305 FreePool (ProblemParam);\r
a405b86d 306 ShellStatus = SHELL_INVALID_PARAMETER;\r
307 } else {\r
47d20b54 308 ASSERT (FALSE);\r
a405b86d 309 }\r
310 } else {\r
311 //\r
312 // check for "-?"\r
313 //\r
47d20b54
MK
314 if (ShellCommandLineGetFlag (Package, L"-?")) {\r
315 ASSERT (FALSE);\r
a405b86d 316 }\r
47d20b54
MK
317\r
318 if (ShellCommandLineGetRawValue (Package, 1) == NULL) {\r
a405b86d 319 //\r
320 // we insufficient parameters\r
321 //\r
47d20b54 322 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"rm");\r
a405b86d 323 ShellStatus = SHELL_INVALID_PARAMETER;\r
324 } else {\r
325 //\r
326 // get a list with each file specified by parameters\r
327 // if parameter is a directory then add all the files below it to the list\r
328 //\r
47d20b54
MK
329 for ( ParamCount = 1, Param = ShellCommandLineGetRawValue (Package, ParamCount)\r
330 ; Param != NULL\r
331 ; ParamCount++, Param = ShellCommandLineGetRawValue (Package, ParamCount)\r
332 )\r
333 {\r
334 Status = ShellOpenFileMetaArg ((CHAR16 *)Param, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);\r
335 if (EFI_ERROR (Status) || (FileList == NULL) || IsListEmpty (&FileList->Link)) {\r
336 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"rm", (CHAR16 *)Param);\r
a405b86d 337 ShellStatus = SHELL_NOT_FOUND;\r
338 break;\r
339 }\r
340 }\r
341\r
47d20b54 342 if (ShellStatus == SHELL_SUCCESS) {\r
a405b86d 343 //\r
344 // loop through the list and make sure we are not aborting...\r
345 //\r
47d20b54
MK
346 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode (&FileList->Link)\r
347 ; !IsNull (&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag ()\r
348 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode (&FileList->Link, &Node->Link)\r
349 )\r
350 {\r
a405b86d 351 //\r
352 // skip the directory traversing stuff...\r
353 //\r
47d20b54 354 if ((StrCmp (Node->FileName, L".") == 0) || (StrCmp (Node->FileName, L"..") == 0)) {\r
a405b86d 355 continue;\r
356 }\r
357\r
358 //\r
359 // do the deleting of nodes\r
360 //\r
47d20b54
MK
361 if (EFI_ERROR (Node->Status)) {\r
362 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR2), gShellLevel2HiiHandle, Node->Status);\r
a405b86d 363 ShellStatus = SHELL_ACCESS_DENIED;\r
364 break;\r
365 }\r
47d20b54
MK
366\r
367 if (!IsValidDeleteTarget (FileList, Node, Package)) {\r
368 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RM_LOG_DELETE_ERR3), gShellLevel2HiiHandle, Node->FullName);\r
a405b86d 369 ShellStatus = SHELL_INVALID_PARAMETER;\r
370 break;\r
371 }\r
372\r
47d20b54 373 ShellStatus = CascadeDelete (Node, ShellCommandLineGetFlag (Package, L"-q"));\r
a405b86d 374 }\r
375 }\r
47d20b54 376\r
a405b86d 377 //\r
378 // Free the fileList\r
379 //\r
380 if (FileList != NULL) {\r
47d20b54 381 Status = ShellCloseFileMetaArg (&FileList);\r
a405b86d 382 }\r
47d20b54 383\r
a405b86d 384 FileList = NULL;\r
385 }\r
386\r
387 //\r
388 // free the command line package\r
389 //\r
390 ShellCommandLineFreeVarList (Package);\r
391 }\r
392\r
393 return (ShellStatus);\r
394}\r