2 Main file for attrib shell level 2 function.
4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "UefiShellLevel2CommandsLib.h"
12 STATIC CONST SHELL_PARAM_ITEM ParamList
[] = {
18 Determine if a directory has no files in it.
20 @param[in] FileHandle The EFI_HANDLE to the directory.
22 @retval TRUE The directory has no files (or directories).
23 @retval FALSE The directory has at least 1 file or directory in it.
27 IN SHELL_FILE_HANDLE FileHandle
31 EFI_FILE_INFO
*FileInfo
;
39 for (Status
= FileHandleFindFirstFile(FileHandle
, &FileInfo
)
40 ; !NoFile
&& !EFI_ERROR (Status
)
41 ; FileHandleFindNextFile(FileHandle
, FileInfo
, &NoFile
)
43 if (StrStr(FileInfo
->FileName
, L
".") != FileInfo
->FileName
44 &&StrStr(FileInfo
->FileName
, L
"..") != FileInfo
->FileName
) {
52 Delete a node and all nodes under it (including sub directories).
54 @param[in] Node The node to start deleting with.
55 @param[in] Quiet TRUE to print no messages.
57 @retval SHELL_SUCCESS The operation was successful.
58 @retval SHELL_ACCESS_DENIED A file was read only.
59 @retval SHELL_ABORTED The abort message was received.
60 @retval SHELL_DEVICE_ERROR A device error occured reading this Node.
64 IN EFI_SHELL_FILE_INFO
*Node
,
65 IN CONST BOOLEAN Quiet
68 SHELL_STATUS ShellStatus
;
69 EFI_SHELL_FILE_INFO
*List
;
70 EFI_SHELL_FILE_INFO
*Node2
;
72 SHELL_PROMPT_RESPONSE
*Resp
;
77 ShellStatus
= SHELL_SUCCESS
;
81 if ((Node
->Info
->Attribute
& EFI_FILE_READ_ONLY
) == EFI_FILE_READ_ONLY
) {
82 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DETELE_RO
), gShellLevel2HiiHandle
, L
"rm", Node
->FullName
);
83 return (SHELL_ACCESS_DENIED
);
86 if ((Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
) {
87 if (!IsDirectoryEmpty(Node
->Handle
)) {
89 Status
= ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN(STR_RM_LOG_DELETE_CONF
), gShellLevel2HiiHandle
, Node
->FullName
);
90 Status
= ShellPromptForResponse(ShellPromptResponseTypeYesNo
, NULL
, (VOID
**)&Resp
);
92 if (EFI_ERROR(Status
) || *Resp
!= ShellPromptResponseYes
) {
93 SHELL_FREE_NON_NULL(Resp
);
94 return (SHELL_ABORTED
);
96 SHELL_FREE_NON_NULL(Resp
);
99 // empty out the directory
101 Status
= gEfiShellProtocol
->FindFilesInDir(Node
->Handle
, &List
);
102 if (EFI_ERROR(Status
)) {
104 gEfiShellProtocol
->FreeFileList(&List
);
106 return (SHELL_DEVICE_ERROR
);
108 for (Node2
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&List
->Link
)
109 ; !IsNull(&List
->Link
, &Node2
->Link
)
110 ; Node2
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&List
->Link
, &Node2
->Link
)
113 // skip the directory traversing stuff...
115 if (StrCmp(Node2
->FileName
, L
".") == 0 || StrCmp(Node2
->FileName
, L
"..") == 0) {
118 Node2
->Status
= gEfiShellProtocol
->OpenFileByName (Node2
->FullName
, &Node2
->Handle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
);
119 if (EFI_ERROR(Node2
->Status
) && StrStr(Node2
->FileName
, L
":") == NULL
) {
121 // Update the node filename to have full path with file system identifier
123 NewSize
= StrSize(Node
->FullName
) + StrSize(Node2
->FullName
);
124 TempName
= AllocateZeroPool(NewSize
);
125 if (TempName
== NULL
) {
126 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
128 StrCpyS(TempName
, NewSize
/sizeof(CHAR16
), Node
->FullName
);
129 TempName
[StrStr(TempName
, L
":")+1-TempName
] = CHAR_NULL
;
130 StrCatS(TempName
, NewSize
/sizeof(CHAR16
), Node2
->FullName
);
131 FreePool((VOID
*)Node2
->FullName
);
132 Node2
->FullName
= TempName
;
135 // Now try again to open the file
137 Node2
->Status
= gEfiShellProtocol
->OpenFileByName (Node2
->FullName
, &Node2
->Handle
, EFI_FILE_MODE_READ
|EFI_FILE_MODE_WRITE
);
140 if (!EFI_ERROR(Node2
->Status
)) {
141 ShellStatus
= CascadeDelete(Node2
, Quiet
);
142 } else if (ShellStatus
== SHELL_SUCCESS
) {
143 ShellStatus
= (SHELL_STATUS
)(Node2
->Status
&(~0x80000000));
145 if (ShellStatus
!= SHELL_SUCCESS
) {
147 gEfiShellProtocol
->FreeFileList(&List
);
149 return (ShellStatus
);
153 gEfiShellProtocol
->FreeFileList(&List
);
158 if (!(StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0)) {
160 // now delete the current node...
163 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DELETE
), gShellLevel2HiiHandle
, Node
->FullName
);
165 Status
= gEfiShellProtocol
->DeleteFile(Node
->Handle
);
170 // We cant allow for the warning here! (Dont use EFI_ERROR Macro).
172 if (Status
!= EFI_SUCCESS
){
173 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DELETE_ERR
), gShellLevel2HiiHandle
, Status
);
174 return (SHELL_ACCESS_DENIED
);
177 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DELETE_COMP
), gShellLevel2HiiHandle
);
179 return (SHELL_SUCCESS
);
184 Determines if a Node is a valid delete target. Will prevent deleting the root directory.
186 @param[in] List RESERVED. Not used.
187 @param[in] Node The node to analyze.
188 @param[in] Package RESERVED. Not used.
192 IN CONST EFI_SHELL_FILE_INFO
*List
,
193 IN CONST EFI_SHELL_FILE_INFO
*Node
,
194 IN CONST LIST_ENTRY
*Package
197 CONST CHAR16
*TempLocation
;
199 CHAR16
*SearchString
;
203 if (Node
== NULL
|| Node
->FullName
== NULL
) {
207 TempLocation
= StrStr(Node
->FullName
, L
":");
208 if (StrLen(TempLocation
) <= 2) {
210 // Deleting the root directory is invalid.
215 TempLocation
= ShellGetCurrentDir(NULL
);
216 if (TempLocation
== NULL
) {
218 // No working directory is specified so whatever is left is ok.
226 Pattern
= StrnCatGrow(&Pattern
, &Size
, TempLocation
, 0);
227 Pattern
= StrnCatGrow(&Pattern
, &Size
, L
"\\" , 0);
229 SearchString
= StrnCatGrow(&SearchString
, &Size
, Node
->FullName
, 0);
230 if (!EFI_ERROR(ShellIsDirectory(SearchString
))) {
231 SearchString
= StrnCatGrow(&SearchString
, &Size
, L
"\\", 0);
232 SearchString
= StrnCatGrow(&SearchString
, &Size
, L
"*", 0);
235 if (Pattern
== NULL
|| SearchString
== NULL
) {
239 if (gUnicodeCollation
->MetaiMatch(gUnicodeCollation
, Pattern
, SearchString
)) {
244 SHELL_FREE_NON_NULL(Pattern
);
245 SHELL_FREE_NON_NULL(SearchString
);
251 Function for 'rm' command.
253 @param[in] ImageHandle Handle to the Image (NULL if Internal).
254 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
259 IN EFI_HANDLE ImageHandle
,
260 IN EFI_SYSTEM_TABLE
*SystemTable
265 CHAR16
*ProblemParam
;
267 SHELL_STATUS ShellStatus
;
269 EFI_SHELL_FILE_INFO
*FileList
;
270 EFI_SHELL_FILE_INFO
*Node
;
273 ShellStatus
= SHELL_SUCCESS
;
278 // initialize the shell lib (we must be in non-auto-init...)
280 Status
= ShellInitialize();
281 ASSERT_EFI_ERROR(Status
);
284 // parse the command line
286 Status
= ShellCommandLineParse (ParamList
, &Package
, &ProblemParam
, TRUE
);
287 if (EFI_ERROR(Status
)) {
288 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
289 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, L
"rm", ProblemParam
);
290 FreePool(ProblemParam
);
291 ShellStatus
= SHELL_INVALID_PARAMETER
;
299 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
302 if (ShellCommandLineGetRawValue(Package
, 1) == NULL
) {
304 // we insufficient parameters
306 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_FEW
), gShellLevel2HiiHandle
, L
"rm");
307 ShellStatus
= SHELL_INVALID_PARAMETER
;
310 // get a list with each file specified by parameters
311 // if parameter is a directory then add all the files below it to the list
313 for ( ParamCount
= 1, Param
= ShellCommandLineGetRawValue(Package
, ParamCount
)
315 ; ParamCount
++, Param
= ShellCommandLineGetRawValue(Package
, ParamCount
)
317 Status
= ShellOpenFileMetaArg((CHAR16
*)Param
, EFI_FILE_MODE_WRITE
|EFI_FILE_MODE_READ
, &FileList
);
318 if (EFI_ERROR(Status
) || FileList
== NULL
|| IsListEmpty(&FileList
->Link
)) {
319 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_FILE_NF
), gShellLevel2HiiHandle
, L
"rm", (CHAR16
*)Param
);
320 ShellStatus
= SHELL_NOT_FOUND
;
325 if (ShellStatus
== SHELL_SUCCESS
){
327 // loop through the list and make sure we are not aborting...
329 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&FileList
->Link
)
330 ; !IsNull(&FileList
->Link
, &Node
->Link
) && !ShellGetExecutionBreakFlag()
331 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&FileList
->Link
, &Node
->Link
)
334 // skip the directory traversing stuff...
336 if (StrCmp(Node
->FileName
, L
".") == 0 || StrCmp(Node
->FileName
, L
"..") == 0) {
341 // do the deleting of nodes
343 if (EFI_ERROR(Node
->Status
)){
344 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DELETE_ERR2
), gShellLevel2HiiHandle
, Node
->Status
);
345 ShellStatus
= SHELL_ACCESS_DENIED
;
348 if (!IsValidDeleteTarget(FileList
, Node
, Package
)) {
349 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_RM_LOG_DELETE_ERR3
), gShellLevel2HiiHandle
, Node
->FullName
);
350 ShellStatus
= SHELL_INVALID_PARAMETER
;
354 ShellStatus
= CascadeDelete(Node
, ShellCommandLineGetFlag(Package
, L
"-q"));
360 if (FileList
!= NULL
) {
361 Status
= ShellCloseFileMetaArg(&FileList
);
367 // free the command line package
369 ShellCommandLineFreeVarList (Package
);
372 return (ShellStatus
);