]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Mv.c
Verify more memory allocations.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Mv.c
1 /** @file
2 Main file for mv shell level 2 function.
3
4 Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "UefiShellLevel2CommandsLib.h"
16
17 /**
18 Function to validate that moving a specific file (FileName) to a specific
19 location (DestPath) is valid.
20
21 This function will verify that the destination is not a subdirectory of
22 FullName, that the Current working Directory is not being moved, and that
23 the directory is not read only.
24
25 if the move is invalid this function will report the error to StdOut.
26
27 @param FullName [in] The name of the file to move.
28 @param Cwd [in] The current working directory
29 @param DestPath [in] The target location to move to
30 @param Attribute[in] The Attribute of the file
31
32 @retval TRUE The move is valid
33 @retval FALSE The move is not
34 **/
35 BOOLEAN
36 EFIAPI
37 IsValidMove(
38 IN CONST CHAR16 *FullName,
39 IN CONST CHAR16 *Cwd,
40 IN CONST CHAR16 *DestPath,
41 IN CONST UINT64 Attribute
42 )
43 {
44 CHAR16 *Test;
45 CHAR16 *Test1;
46 CHAR16 *TestWalker;
47 INTN Result;
48 UINTN TempLen;
49 if (Cwd != NULL && StrCmp(FullName, Cwd) == 0) {
50 //
51 // Invalid move
52 //
53 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_CWD), gShellLevel2HiiHandle);
54 return (FALSE);
55 }
56 Test = NULL;
57 Test = StrnCatGrow(&Test, NULL, DestPath, 0);
58 TestWalker = Test;
59 ASSERT(TestWalker != NULL);
60 while(*TestWalker == L'\\') {
61 TestWalker++;
62 }
63 while(TestWalker != NULL && TestWalker[StrLen(TestWalker)-1] == L'\\') {
64 TestWalker[StrLen(TestWalker)-1] = CHAR_NULL;
65 }
66 ASSERT(TestWalker != NULL);
67 ASSERT(FullName != NULL);
68 if (StrStr(FullName, TestWalker) != 0) {
69 TempLen = StrLen(FullName);
70 if (StrStr(FullName, TestWalker) != FullName // not the first items... (could below it)
71 && TempLen <= (StrLen(TestWalker) + 1)
72 && StrStr(FullName+StrLen(TestWalker) + 1, L"\\") == NULL) {
73 //
74 // Invalid move
75 //
76 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
77 FreePool(Test);
78 return (FALSE);
79 }
80 }
81 FreePool(Test);
82 if (StrStr(DestPath, FullName) != 0 && StrStr(DestPath, FullName) != DestPath) {
83 //
84 // Invalid move
85 //
86 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_SUB), gShellLevel2HiiHandle);
87 return (FALSE);
88 }
89 if ((Attribute & EFI_FILE_READ_ONLY) != 0) {
90 //
91 // invalid to move read only
92 //
93 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_RO), gShellLevel2HiiHandle);
94 return (FALSE);
95 }
96 Test = StrStr(FullName, L":");
97 Test1 = StrStr(DestPath, L":");
98 if (Test1 != NULL && Test != NULL) {
99 *Test = CHAR_NULL;
100 *Test1 = CHAR_NULL;
101 Result = StringNoCaseCompare(&FullName, &DestPath);
102 *Test = L':';
103 *Test1 = L':';
104 if (Result != 0) {
105 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_MV_INV_FS), gShellLevel2HiiHandle);
106 return (FALSE);
107 }
108 }
109 return (TRUE);
110 }
111
112 /**
113 Function to take a destination path that might contain wildcards and verify
114 that there is only a single possible target (IE we cant have wildcards that
115 have 2 possible destination).
116
117 if the result is sucessful the caller must free *DestPathPointer.
118
119 @param[in] DestDir The original path to the destination
120 @param[in,out] DestPathPointer a pointer to the callee allocated final path.
121
122 @retval EFI_INVALID_PARAMETR the DestDir could not be resolved to a location
123 @retval EFI_INVALID_PARAMETR the DestDir could be resolved to more than 1 location
124 @retval EFI_SUCCESS the operation was sucessful
125 **/
126 SHELL_STATUS
127 EFIAPI
128 GetDestinationLocation(
129 IN CONST CHAR16 *DestDir,
130 IN OUT CHAR16 **DestPathPointer,
131 IN CONST CHAR16 *Cwd
132 )
133 {
134 EFI_SHELL_FILE_INFO *DestList;
135 EFI_SHELL_FILE_INFO *Node;
136 EFI_STATUS Status;
137 CHAR16 *DestPath;
138 CHAR16 *TempLocation;
139 UINTN NewSize;
140
141 DestList = NULL;
142 DestPath = NULL;
143 //
144 // get the destination path
145 //
146 Status = ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ|EFI_FILE_MODE_CREATE, &DestList);
147 if (DestList == NULL || IsListEmpty(&DestList->Link)) {
148 //
149 // Not existing... must be renaming
150 //
151 if ((TempLocation = StrStr(DestDir, L":")) == NULL) {
152 NewSize = StrSize(Cwd);
153 NewSize += StrSize(DestDir);
154 DestPath = AllocateZeroPool(NewSize);
155 if (DestPath == NULL) {
156 ShellCloseFileMetaArg(&DestList);
157 return (SHELL_OUT_OF_RESOURCES);
158 }
159 StrCpy(DestPath, Cwd);
160 if (DestPath[StrLen(DestPath)-1] != L'\\' && DestDir[0] != L'\\') {
161 StrCat(DestPath, L"\\");
162 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && DestDir[0] == L'\\') {
163 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL;
164 }
165 StrCat(DestPath, DestDir);
166 } else {
167 ASSERT(DestPath == NULL);
168 DestPath = StrnCatGrow(&DestPath, NULL, DestDir, 0);
169 if (DestPath == NULL) {
170 ShellCloseFileMetaArg(&DestList);
171 return (SHELL_OUT_OF_RESOURCES);
172 }
173 }
174 } else {
175 Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&DestList->Link);
176 //
177 // Make sure there is only 1 node in the list.
178 //
179 if (!IsNodeAtEnd(&DestList->Link, &Node->Link)) {
180 ShellCloseFileMetaArg(&DestList);
181 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir);
182 return (SHELL_INVALID_PARAMETER);
183 }
184 if (ShellIsDirectory(Node->FullName)==EFI_SUCCESS) {
185 DestPath = AllocateZeroPool(StrSize(Node->FullName)+sizeof(CHAR16));
186 if (DestPath == NULL) {
187 ShellCloseFileMetaArg(&DestList);
188 return (SHELL_OUT_OF_RESOURCES);
189 }
190 StrCpy(DestPath, Node->FullName);
191 StrCat(DestPath, L"\\");
192 } else {
193 //
194 // cant move onto another file.
195 //
196 ShellCloseFileMetaArg(&DestList);
197 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_ERROR), gShellLevel2HiiHandle, DestDir);
198 return (SHELL_INVALID_PARAMETER);
199 }
200 }
201
202 *DestPathPointer = DestPath;
203 ShellCloseFileMetaArg(&DestList);
204
205 return (SHELL_SUCCESS);
206 }
207
208 /**
209 function to take a list of files to move and a destination location and do
210 the verification and moving of those files to that location. This function
211 will report any errors to the user and continue to move the rest of the files.
212
213 @param[in] FileList A LIST_ENTRY* based list of files to move
214 @param[in] DestDir the destination location
215
216 @retval SHELL_SUCCESS the files were all moved.
217 @retval SHELL_INVALID_PARAMETER a parameter was invalid
218 @retval SHELL_SECURITY_VIOLATION a security violation ocurred
219 @retval SHELL_WRITE_PROTECTED the destination was write protected
220 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed
221 **/
222 SHELL_STATUS
223 EFIAPI
224 ValidateAndMoveFiles(
225 IN CONST EFI_SHELL_FILE_INFO *FileList,
226 IN CONST CHAR16 *DestDir
227 )
228 {
229 EFI_STATUS Status;
230 CHAR16 *HiiOutput;
231 CHAR16 *HiiResultOk;
232 CHAR16 *DestPath;
233 CONST CHAR16 *Cwd;
234 SHELL_STATUS ShellStatus;
235 CONST EFI_SHELL_FILE_INFO *Node;
236 EFI_FILE_INFO *NewFileInfo;
237 CHAR16 *TempLocation;
238 UINTN NewSize;
239 UINTN Length;
240
241 ASSERT(FileList != NULL);
242 ASSERT(DestDir != NULL);
243
244 DestPath = NULL;
245 Cwd = ShellGetCurrentDir(NULL);
246
247 //
248 // Get and validate the destination location
249 //
250 ShellStatus = GetDestinationLocation(DestDir, &DestPath, Cwd);
251 if (ShellStatus != SHELL_SUCCESS) {
252 return (ShellStatus);
253 }
254
255 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_MV_OUTPUT), NULL);
256 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL);
257 ASSERT (DestPath != NULL);
258 ASSERT (HiiResultOk != NULL);
259 ASSERT (HiiOutput != NULL);
260 // ASSERT (Cwd != NULL);
261
262 //
263 // Go through the list of files and directories to move...
264 //
265 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link)
266 ; !IsNull(&FileList->Link, &Node->Link)
267 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link)
268 ){
269 if (ShellGetExecutionBreakFlag()) {
270 break;
271 }
272 ASSERT(Node->FileName != NULL);
273 ASSERT(Node->FullName != NULL);
274
275 //
276 // skip the directory traversing stuff...
277 //
278 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) {
279 continue;
280 }
281
282 //
283 // Validate that the move is valid
284 //
285 if (!IsValidMove(Node->FullName, Cwd, DestPath, Node->Info->Attribute)) {
286 ShellStatus = SHELL_INVALID_PARAMETER;
287 continue;
288 }
289
290 //
291 // Chop off map info from "DestPath"
292 //
293 if ((TempLocation = StrStr(DestPath, L":")) != NULL) {
294 CopyMem(DestPath, TempLocation+1, StrSize(TempLocation+1));
295 }
296
297 //
298 // construct the new file info block
299 //
300 NewSize = StrSize(DestPath);
301 NewSize += StrSize(Node->FileName) + sizeof(EFI_FILE_INFO) + sizeof(CHAR16);
302 NewFileInfo = AllocateZeroPool(NewSize);
303 if (NewFileInfo == NULL) {
304 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
305 ShellStatus = SHELL_OUT_OF_RESOURCES;
306 } else {
307 CopyMem(NewFileInfo, Node->Info, sizeof(EFI_FILE_INFO));
308 if (DestPath[0] != L'\\') {
309 StrCpy(NewFileInfo->FileName, L"\\");
310 StrCat(NewFileInfo->FileName, DestPath);
311 } else {
312 StrCpy(NewFileInfo->FileName, DestPath);
313 }
314 Length = StrLen(NewFileInfo->FileName);
315 if (Length > 0) {
316 Length--;
317 }
318 if (NewFileInfo->FileName[Length] == L'\\') {
319 if (Node->FileName[0] == L'\\') {
320 //
321 // Don't allow for double slashes. Eliminate one of them.
322 //
323 NewFileInfo->FileName[Length] = CHAR_NULL;
324 }
325 StrCat(NewFileInfo->FileName, Node->FileName);
326 }
327 NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFileInfo->FileName);
328
329 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, NewFileInfo->FileName);
330
331 //
332 // Perform the move operation
333 //
334 Status = ShellSetFileInfo(Node->Handle, NewFileInfo);
335
336 //
337 // Free the info object we used...
338 //
339 ASSERT (NewFileInfo != NULL);
340 FreePool(NewFileInfo);
341
342 //
343 // Check our result
344 //
345 if (EFI_ERROR(Status)) {
346 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_UK), gShellLevel2HiiHandle, Status);
347 //
348 // move failed
349 //
350 switch(Status){
351 default:
352 ShellStatus = SHELL_INVALID_PARAMETER;
353 case EFI_SECURITY_VIOLATION:
354 ShellStatus = SHELL_SECURITY_VIOLATION;
355 case EFI_WRITE_PROTECTED:
356 ShellStatus = SHELL_WRITE_PROTECTED;
357 case EFI_OUT_OF_RESOURCES:
358 ShellStatus = SHELL_OUT_OF_RESOURCES;
359 case EFI_DEVICE_ERROR:
360 ShellStatus = SHELL_DEVICE_ERROR;
361 case EFI_ACCESS_DENIED:
362 ShellStatus = SHELL_ACCESS_DENIED;
363 } // switch
364 } else {
365 ShellPrintEx(-1, -1, L"%s", HiiResultOk);
366 }
367 }
368 } // for loop
369
370 FreePool(DestPath);
371 FreePool(HiiOutput);
372 FreePool(HiiResultOk);
373 return (ShellStatus);
374 }
375
376 SHELL_STATUS
377 EFIAPI
378 ShellCommandRunMv (
379 IN EFI_HANDLE ImageHandle,
380 IN EFI_SYSTEM_TABLE *SystemTable
381 )
382 {
383 EFI_STATUS Status;
384 LIST_ENTRY *Package;
385 CHAR16 *ProblemParam;
386 SHELL_STATUS ShellStatus;
387 UINTN ParamCount;
388 UINTN LoopCounter;
389 EFI_SHELL_FILE_INFO *FileList;
390
391 ProblemParam = NULL;
392 ShellStatus = SHELL_SUCCESS;
393 ParamCount = 0;
394 FileList = NULL;
395
396 //
397 // initialize the shell lib (we must be in non-auto-init...)
398 //
399 Status = ShellInitialize();
400 ASSERT_EFI_ERROR(Status);
401
402 //
403 // parse the command line
404 //
405 Status = ShellCommandLineParse (EmptyParamList, &Package, &ProblemParam, TRUE);
406 if (EFI_ERROR(Status)) {
407 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
408 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
409 FreePool(ProblemParam);
410 ShellStatus = SHELL_INVALID_PARAMETER;
411 } else {
412 ASSERT(FALSE);
413 }
414 } else {
415 //
416 // check for "-?"
417 //
418 if (ShellCommandLineGetFlag(Package, L"-?")) {
419 ASSERT(FALSE);
420 }
421
422 switch (ParamCount = ShellCommandLineGetCount(Package)) {
423 case 0:
424 case 1:
425 //
426 // we have insufficient parameters
427 //
428 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle);
429 ShellStatus = SHELL_INVALID_PARAMETER;
430 break;
431 case 2:
432 //
433 // must have valid CWD for single parameter...
434 //
435 if (ShellGetCurrentDir(NULL) == NULL){
436 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
437 ShellStatus = SHELL_INVALID_PARAMETER;
438 } else {
439 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
440 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
441 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
442 ShellStatus = SHELL_NOT_FOUND;
443 } else {
444 //
445 // ValidateAndMoveFiles will report errors to the screen itself
446 //
447 ShellStatus = ValidateAndMoveFiles(FileList, ShellGetCurrentDir(NULL));
448 }
449 }
450
451 break;
452 default:
453 ///@todo make sure this works with error half way through and continues...
454 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) {
455 if (ShellGetExecutionBreakFlag()) {
456 break;
457 }
458 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList);
459 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) {
460 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1));
461 ShellStatus = SHELL_NOT_FOUND;
462 } else {
463 //
464 // ValidateAndMoveFiles will report errors to the screen itself
465 // Only change ShellStatus if it's sucessful
466 //
467 if (ShellStatus == SHELL_SUCCESS) {
468 ShellStatus = ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount));
469 } else {
470 ValidateAndMoveFiles(FileList, ShellCommandLineGetRawValue(Package, ParamCount));
471 }
472 }
473 if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
474 Status = ShellCloseFileMetaArg(&FileList);
475 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) {
476 ShellStatus = SHELL_ACCESS_DENIED;
477 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, ShellCommandLineGetRawValue(Package, 1), ShellStatus|MAX_BIT);
478 }
479 }
480 }
481 break;
482 } // switch on parameter count
483
484 if (FileList != NULL) {
485 ShellCloseFileMetaArg(&FileList);
486 }
487
488 //
489 // free the command line package
490 //
491 ShellCommandLineFreeVarList (Package);
492 }
493
494 if (ShellGetExecutionBreakFlag()) {
495 return (SHELL_ABORTED);
496 }
497
498 return (ShellStatus);
499 }