Cp.c revision 099e8ff5d2876b1d1606c3424114969946c15173
111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/** @file 211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert Main file for cp shell level 2 function. 311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert Copyright (c) 2015, Hewlett-Packard Development Company, L.P.<BR> 511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR> 611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert This program and the accompanying materials 711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert are licensed and made available under the terms and conditions of the BSD License 811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert which accompanies this distribution. The full text of the license may be found at 911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert http://opensource.org/licenses/bsd-license.php 1011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 1111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 1211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 1311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 1411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert**/ 1511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 1611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include "UefiShellLevel2CommandsLib.h" 1711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <Guid/FileSystemInfo.h> 1811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert#include <Guid/FileSystemVolumeLabelInfo.h> 1911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 2011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert/** 2111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert Function to take a list of files to copy and a destination location and do 2211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert the verification and copying of those files to that location. This function 2311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert will report any errors to the user and halt. 2411cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 2511cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @param[in] FileList A LIST_ENTRY* based list of files to move. 2611cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @param[in] DestDir The destination location. 2711cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @param[in] SilentMode TRUE to eliminate screen output. 2811cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @param[in] RecursiveMode TRUE to copy directories. 2911cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @param[in] Resp The response to the overwrite query (if always). 3011cd02dfb91661c65134cac258cf5924270e9d2Dan Albert 3111cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @retval SHELL_SUCCESS the files were all moved. 3211cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @retval SHELL_INVALID_PARAMETER a parameter was invalid 3311cd02dfb91661c65134cac258cf5924270e9d2Dan Albert @retval SHELL_SECURITY_VIOLATION a security violation ocurred 34 @retval SHELL_WRITE_PROTECTED the destination was write protected 35 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed 36**/ 37SHELL_STATUS 38EFIAPI 39ValidateAndCopyFiles( 40 IN CONST EFI_SHELL_FILE_INFO *FileList, 41 IN CONST CHAR16 *DestDir, 42 IN BOOLEAN SilentMode, 43 IN BOOLEAN RecursiveMode, 44 IN VOID **Resp 45 ); 46 47/** 48 Function to Copy one file to another location 49 50 If the destination exists the user will be prompted and the result put into *resp 51 52 @param[in] Source pointer to source file name 53 @param[in] Dest pointer to destination file name 54 @param[out] Resp pointer to response from question. Pass back on looped calling 55 @param[in] SilentMode whether to run in quiet mode or not 56 57 @retval SHELL_SUCCESS The source file was copied to the destination 58**/ 59SHELL_STATUS 60EFIAPI 61CopySingleFile( 62 IN CONST CHAR16 *Source, 63 IN CONST CHAR16 *Dest, 64 OUT VOID **Resp, 65 IN BOOLEAN SilentMode 66 ) 67{ 68 VOID *Response; 69 UINTN ReadSize; 70 SHELL_FILE_HANDLE SourceHandle; 71 SHELL_FILE_HANDLE DestHandle; 72 EFI_STATUS Status; 73 VOID *Buffer; 74 CHAR16 *TempName; 75 UINTN Size; 76 EFI_SHELL_FILE_INFO *List; 77 SHELL_STATUS ShellStatus; 78 UINT64 SourceFileSize; 79 UINT64 DestFileSize; 80 EFI_FILE_PROTOCOL *DestVolumeFP; 81 EFI_FILE_SYSTEM_INFO *DestVolumeInfo; 82 UINTN DestVolumeInfoSize; 83 84 ASSERT(Resp != NULL); 85 86 SourceHandle = NULL; 87 DestHandle = NULL; 88 Response = *Resp; 89 List = NULL; 90 DestVolumeInfo = NULL; 91 ShellStatus = SHELL_SUCCESS; 92 93 ReadSize = PcdGet32(PcdShellFileOperationSize); 94 // Why bother copying a file to itself 95 if (StrCmp(Source, Dest) == 0) { 96 return (SHELL_SUCCESS); 97 } 98 99 // 100 // if the destination file existed check response and possibly prompt user 101 // 102 if (ShellFileExists(Dest) == EFI_SUCCESS) { 103 if (Response == NULL && !SilentMode) { 104 Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); 105 } 106 // 107 // possibly return based on response 108 // 109 if (!SilentMode) { 110 switch (*(SHELL_PROMPT_RESPONSE*)Response) { 111 case ShellPromptResponseNo: 112 // 113 // return success here so we dont stop the process 114 // 115 return (SHELL_SUCCESS); 116 case ShellPromptResponseCancel: 117 *Resp = Response; 118 // 119 // indicate to stop everything 120 // 121 return (SHELL_ABORTED); 122 case ShellPromptResponseAll: 123 *Resp = Response; 124 case ShellPromptResponseYes: 125 break; 126 default: 127 return SHELL_ABORTED; 128 } 129 } 130 } 131 132 if (ShellIsDirectory(Source) == EFI_SUCCESS) { 133 Status = ShellCreateDirectory(Dest, &DestHandle); 134 if (EFI_ERROR(Status)) { 135 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_DIR_FAIL), gShellLevel2HiiHandle, L"cp", Dest); 136 return (SHELL_ACCESS_DENIED); 137 } 138 139 // 140 // Now copy all the files under the directory... 141 // 142 TempName = NULL; 143 Size = 0; 144 StrnCatGrow(&TempName, &Size, Source, 0); 145 StrnCatGrow(&TempName, &Size, L"\\*", 0); 146 if (TempName != NULL) { 147 ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List); 148 *TempName = CHAR_NULL; 149 StrnCatGrow(&TempName, &Size, Dest, 0); 150 StrnCatGrow(&TempName, &Size, L"\\", 0); 151 ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp); 152 ShellCloseFileMetaArg(&List); 153 SHELL_FREE_NON_NULL(TempName); 154 Size = 0; 155 } 156 } else { 157 Status = ShellDeleteFileByName(Dest); 158 159 // 160 // open file with create enabled 161 // 162 Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); 163 if (EFI_ERROR(Status)) { 164 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_OPEN_FAIL), gShellLevel2HiiHandle, L"cp", Dest); 165 return (SHELL_ACCESS_DENIED); 166 } 167 168 // 169 // open source file 170 // 171 Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0); 172 ASSERT_EFI_ERROR(Status); 173 174 // 175 //get file size of source file and freespace available on destination volume 176 // 177 ShellGetFileSize(SourceHandle, &SourceFileSize); 178 ShellGetFileSize(DestHandle, &DestFileSize); 179 180 // 181 //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space 182 // 183 if(DestFileSize < SourceFileSize){ 184 SourceFileSize -= DestFileSize; 185 } else { 186 SourceFileSize = 0; 187 } 188 189 // 190 //get the system volume info to check the free space 191 // 192 DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle); 193 DestVolumeInfo = NULL; 194 DestVolumeInfoSize = 0; 195 Status = DestVolumeFP->GetInfo( 196 DestVolumeFP, 197 &gEfiFileSystemInfoGuid, 198 &DestVolumeInfoSize, 199 DestVolumeInfo 200 ); 201 202 if (Status == EFI_BUFFER_TOO_SMALL) { 203 DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize); 204 Status = DestVolumeFP->GetInfo( 205 DestVolumeFP, 206 &gEfiFileSystemInfoGuid, 207 &DestVolumeInfoSize, 208 DestVolumeInfo 209 ); 210 } 211 212 // 213 //check if enough space available on destination drive to complete copy 214 // 215 if (DestVolumeInfo!= NULL && (DestVolumeInfo->FreeSpace < SourceFileSize)) { 216 // 217 //not enough space on destination directory to copy file 218 // 219 SHELL_FREE_NON_NULL(DestVolumeInfo); 220 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle, L"cp"); 221 return(SHELL_VOLUME_FULL); 222 } else { 223 // 224 // copy data between files 225 // 226 Buffer = AllocateZeroPool(ReadSize); 227 ASSERT(Buffer != NULL); 228 while (ReadSize == PcdGet32(PcdShellFileOperationSize) && !EFI_ERROR(Status)) { 229 Status = ShellReadFile(SourceHandle, &ReadSize, Buffer); 230 if (!EFI_ERROR(Status)) { 231 Status = ShellWriteFile(DestHandle, &ReadSize, Buffer); 232 if (EFI_ERROR(Status)) { 233 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); 234 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_WRITE_ERROR), gShellLevel2HiiHandle, L"cp", Dest); 235 break; 236 } 237 } else { 238 ShellStatus = (SHELL_STATUS) (Status & (~MAX_BIT)); 239 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_READ_ERROR), gShellLevel2HiiHandle, L"cp", Source); 240 break; 241 } 242 } 243 } 244 SHELL_FREE_NON_NULL(DestVolumeInfo); 245 } 246 247 // 248 // close files 249 // 250 if (DestHandle != NULL) { 251 ShellCloseFile(&DestHandle); 252 DestHandle = NULL; 253 } 254 if (SourceHandle != NULL) { 255 ShellCloseFile(&SourceHandle); 256 SourceHandle = NULL; 257 } 258 259 // 260 // return 261 // 262 return ShellStatus; 263} 264 265/** 266 function to take a list of files to copy and a destination location and do 267 the verification and copying of those files to that location. This function 268 will report any errors to the user and halt. 269 270 The key is to have this function called ONLY once. this allows for the parameter 271 verification to happen correctly. 272 273 @param[in] FileList A LIST_ENTRY* based list of files to move. 274 @param[in] DestDir The destination location. 275 @param[in] SilentMode TRUE to eliminate screen output. 276 @param[in] RecursiveMode TRUE to copy directories. 277 @param[in] Resp The response to the overwrite query (if always). 278 279 @retval SHELL_SUCCESS the files were all moved. 280 @retval SHELL_INVALID_PARAMETER a parameter was invalid 281 @retval SHELL_SECURITY_VIOLATION a security violation ocurred 282 @retval SHELL_WRITE_PROTECTED the destination was write protected 283 @retval SHELL_OUT_OF_RESOURCES a memory allocation failed 284**/ 285SHELL_STATUS 286EFIAPI 287ValidateAndCopyFiles( 288 IN CONST EFI_SHELL_FILE_INFO *FileList, 289 IN CONST CHAR16 *DestDir, 290 IN BOOLEAN SilentMode, 291 IN BOOLEAN RecursiveMode, 292 IN VOID **Resp 293 ) 294{ 295 CHAR16 *HiiOutput; 296 CHAR16 *HiiResultOk; 297 CONST EFI_SHELL_FILE_INFO *Node; 298 SHELL_STATUS ShellStatus; 299 EFI_STATUS Status; 300 CHAR16 *DestPath; 301 VOID *Response; 302 UINTN PathSize; 303 CONST CHAR16 *Cwd; 304 UINTN NewSize; 305 CHAR16 *CleanFilePathStr; 306 307 if (Resp == NULL) { 308 Response = NULL; 309 } else { 310 Response = *Resp; 311 } 312 313 DestPath = NULL; 314 ShellStatus = SHELL_SUCCESS; 315 PathSize = 0; 316 Cwd = ShellGetCurrentDir(NULL); 317 CleanFilePathStr = NULL; 318 319 ASSERT(FileList != NULL); 320 ASSERT(DestDir != NULL); 321 322 323 Status = ShellLevel2StripQuotes (DestDir, &CleanFilePathStr); 324 if (EFI_ERROR (Status)) { 325 if (Status == EFI_OUT_OF_RESOURCES) { 326 return SHELL_OUT_OF_RESOURCES; 327 } else { 328 return SHELL_INVALID_PARAMETER; 329 } 330 } 331 332 ASSERT (CleanFilePathStr != NULL); 333 334 // 335 // If we are trying to copy multiple files... make sure we got a directory for the target... 336 // 337 if (EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) && FileList->Link.ForwardLink != FileList->Link.BackLink) { 338 // 339 // Error for destination not a directory 340 // 341 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); 342 FreePool (CleanFilePathStr); 343 return (SHELL_INVALID_PARAMETER); 344 } 345 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) 346 ; !IsNull(&FileList->Link, &Node->Link) 347 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) 348 ){ 349 // 350 // skip the directory traversing stuff... 351 // 352 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { 353 continue; 354 } 355 356 NewSize = StrSize(CleanFilePathStr); 357 NewSize += StrSize(Node->FullName); 358 NewSize += (Cwd == NULL)? 0 : StrSize(Cwd); 359 if (NewSize > PathSize) { 360 PathSize = NewSize; 361 } 362 363 // 364 // Make sure got -r if required 365 // 366 if (!RecursiveMode && !EFI_ERROR(ShellIsDirectory(Node->FullName))) { 367 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_REQ), gShellLevel2HiiHandle, L"cp"); 368 FreePool (CleanFilePathStr); 369 return (SHELL_INVALID_PARAMETER); 370 } 371 372 // 373 // make sure got dest as dir if needed 374 // 375 if (!EFI_ERROR(ShellIsDirectory(Node->FullName)) && EFI_ERROR(ShellIsDirectory(CleanFilePathStr))) { 376 // 377 // Error for destination not a directory 378 // 379 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NOT_DIR), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); 380 FreePool (CleanFilePathStr); 381 return (SHELL_INVALID_PARAMETER); 382 } 383 } 384 385 HiiOutput = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_CP_OUTPUT), NULL); 386 HiiResultOk = HiiGetString (gShellLevel2HiiHandle, STRING_TOKEN (STR_GEN_RES_OK), NULL); 387 DestPath = AllocateZeroPool(PathSize); 388 389 if (DestPath == NULL || HiiOutput == NULL || HiiResultOk == NULL) { 390 SHELL_FREE_NON_NULL(DestPath); 391 SHELL_FREE_NON_NULL(HiiOutput); 392 SHELL_FREE_NON_NULL(HiiResultOk); 393 FreePool (CleanFilePathStr); 394 return (SHELL_OUT_OF_RESOURCES); 395 } 396 397 // 398 // Go through the list of files to copy... 399 // 400 for (Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&FileList->Link) 401 ; !IsNull(&FileList->Link, &Node->Link) 402 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&FileList->Link, &Node->Link) 403 ){ 404 if (ShellGetExecutionBreakFlag()) { 405 break; 406 } 407 ASSERT(Node->FileName != NULL); 408 ASSERT(Node->FullName != NULL); 409 410 // 411 // skip the directory traversing stuff... 412 // 413 if (StrCmp(Node->FileName, L".") == 0 || StrCmp(Node->FileName, L"..") == 0) { 414 continue; 415 } 416 417 if (FileList->Link.ForwardLink == FileList->Link.BackLink // 1 item 418 && EFI_ERROR(ShellIsDirectory(CleanFilePathStr)) // not an existing directory 419 ) { 420 if (StrStr(CleanFilePathStr, L":") == NULL) { 421 // 422 // simple copy of a single file 423 // 424 if (Cwd != NULL) { 425 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16)-1); 426 } else { 427 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); 428 FreePool (CleanFilePathStr); 429 return (SHELL_INVALID_PARAMETER); 430 } 431 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') { 432 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 433 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') { 434 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; 435 } 436 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 437 } else { 438 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1); 439 } 440 } else { 441 // 442 // we have multiple files or a directory in the DestDir 443 // 444 445 // 446 // Check for leading slash 447 // 448 if (CleanFilePathStr[0] == L'\\') { 449 // 450 // Copy to the root of CWD 451 // 452 if (Cwd != NULL) { 453 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1); 454 } else { 455 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); 456 FreePool(CleanFilePathStr); 457 return (SHELL_INVALID_PARAMETER); 458 } 459 while (PathRemoveLastItem(DestPath)); 460 StrnCat(DestPath, CleanFilePathStr+1, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 461 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 462 } else if (StrStr(CleanFilePathStr, L":") == NULL) { 463 if (Cwd != NULL) { 464 StrnCpy(DestPath, Cwd, PathSize/sizeof(CHAR16) -1); 465 } else { 466 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_DIR_NF), gShellLevel2HiiHandle, L"cp", CleanFilePathStr); 467 FreePool(CleanFilePathStr); 468 return (SHELL_INVALID_PARAMETER); 469 } 470 if (DestPath[StrLen(DestPath)-1] != L'\\' && CleanFilePathStr[0] != L'\\') { 471 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 472 } else if (DestPath[StrLen(DestPath)-1] == L'\\' && CleanFilePathStr[0] == L'\\') { 473 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; 474 } 475 StrnCat(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 476 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') { 477 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 478 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') { 479 ((CHAR16*)DestPath)[StrLen(DestPath)-1] = CHAR_NULL; 480 } 481 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 482 483 } else { 484 StrnCpy(DestPath, CleanFilePathStr, PathSize/sizeof(CHAR16) -1); 485 if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] != L'\\' && Node->FileName[0] != L'\\') { 486 StrnCat(DestPath, L"\\", PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 487 } else if (CleanFilePathStr[StrLen(CleanFilePathStr)-1] == L'\\' && Node->FileName[0] == L'\\') { 488 ((CHAR16*)CleanFilePathStr)[StrLen(CleanFilePathStr)-1] = CHAR_NULL; 489 } 490 StrnCat(DestPath, Node->FileName, PathSize/sizeof(CHAR16) - StrLen(DestPath) -1); 491 } 492 } 493 494 // 495 // Make sure the path exists 496 // 497 if (EFI_ERROR(VerifyIntermediateDirectories(DestPath))) { 498 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DIR_WNF), gShellLevel2HiiHandle, L"cp", DestPath); 499 ShellStatus = SHELL_DEVICE_ERROR; 500 break; 501 } 502 503 if ( !EFI_ERROR(ShellIsDirectory(Node->FullName)) 504 && !EFI_ERROR(ShellIsDirectory(DestPath)) 505 && StrniCmp(Node->FullName, DestPath, StrLen(DestPath)) == NULL 506 ){ 507 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_PARENT), gShellLevel2HiiHandle, L"cp"); 508 ShellStatus = SHELL_INVALID_PARAMETER; 509 break; 510 } 511 if (StringNoCaseCompare(&Node->FullName, &DestPath) == 0) { 512 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); 513 ShellStatus = SHELL_INVALID_PARAMETER; 514 break; 515 } 516 517 if ((StrniCmp(Node->FullName, DestPath, StrLen(Node->FullName)) == 0) 518 && (DestPath[StrLen(Node->FullName)] == CHAR_NULL || DestPath[StrLen(Node->FullName)] == L'\\') 519 ) { 520 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_SD_SAME), gShellLevel2HiiHandle, L"cp"); 521 ShellStatus = SHELL_INVALID_PARAMETER; 522 break; 523 } 524 525 PathCleanUpDirectories(DestPath); 526 527 if (!SilentMode) { 528 ShellPrintEx(-1, -1, HiiOutput, Node->FullName, DestPath); 529 } 530 531 // 532 // copy single file... 533 // 534 ShellStatus = CopySingleFile(Node->FullName, DestPath, &Response, SilentMode); 535 if (ShellStatus != SHELL_SUCCESS) { 536 break; 537 } 538 } 539 if (ShellStatus == SHELL_SUCCESS && Resp == NULL) { 540 ShellPrintEx(-1, -1, L"%s", HiiResultOk); 541 } 542 543 SHELL_FREE_NON_NULL(DestPath); 544 SHELL_FREE_NON_NULL(HiiOutput); 545 SHELL_FREE_NON_NULL(HiiResultOk); 546 SHELL_FREE_NON_NULL(CleanFilePathStr); 547 if (Resp == NULL) { 548 SHELL_FREE_NON_NULL(Response); 549 } 550 551 return (ShellStatus); 552 553} 554 555/** 556 Validate and if successful copy all the files from the list into 557 destination directory. 558 559 @param[in] FileList The list of files to copy. 560 @param[in] DestDir The directory to copy files to. 561 @param[in] SilentMode TRUE to eliminate screen output. 562 @param[in] RecursiveMode TRUE to copy directories. 563 564 @retval SHELL_INVALID_PARAMETER A parameter was invalid. 565 @retval SHELL_SUCCESS The operation was successful. 566**/ 567SHELL_STATUS 568EFIAPI 569ProcessValidateAndCopyFiles( 570 IN EFI_SHELL_FILE_INFO *FileList, 571 IN CONST CHAR16 *DestDir, 572 IN BOOLEAN SilentMode, 573 IN BOOLEAN RecursiveMode 574 ) 575{ 576 SHELL_STATUS ShellStatus; 577 EFI_SHELL_FILE_INFO *List; 578 EFI_FILE_INFO *FileInfo; 579 CHAR16 *FullName; 580 581 List = NULL; 582 FullName = NULL; 583 FileInfo = NULL; 584 585 ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List); 586 if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) { 587 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, L"cp", DestDir); 588 ShellStatus = SHELL_INVALID_PARAMETER; 589 ShellCloseFileMetaArg(&List); 590 } else if (List != NULL) { 591 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL); 592 ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL); 593 FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle); 594 ASSERT(FileInfo != NULL); 595 StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0); 596 ShellCloseFileMetaArg(&List); 597 if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) { 598 ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL); 599 } else { 600 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle, L"cp"); 601 ShellStatus = SHELL_ACCESS_DENIED; 602 } 603 } else { 604 ShellCloseFileMetaArg(&List); 605 ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL); 606 } 607 608 SHELL_FREE_NON_NULL(FileInfo); 609 SHELL_FREE_NON_NULL(FullName); 610 return (ShellStatus); 611} 612 613STATIC CONST SHELL_PARAM_ITEM ParamList[] = { 614 {L"-r", TypeFlag}, 615 {L"-q", TypeFlag}, 616 {NULL, TypeMax} 617 }; 618 619/** 620 Function for 'cp' command. 621 622 @param[in] ImageHandle Handle to the Image (NULL if Internal). 623 @param[in] SystemTable Pointer to the System Table (NULL if Internal). 624**/ 625SHELL_STATUS 626EFIAPI 627ShellCommandRunCp ( 628 IN EFI_HANDLE ImageHandle, 629 IN EFI_SYSTEM_TABLE *SystemTable 630 ) 631{ 632 EFI_STATUS Status; 633 LIST_ENTRY *Package; 634 CHAR16 *ProblemParam; 635 SHELL_STATUS ShellStatus; 636 UINTN ParamCount; 637 UINTN LoopCounter; 638 EFI_SHELL_FILE_INFO *FileList; 639 BOOLEAN SilentMode; 640 BOOLEAN RecursiveMode; 641 CONST CHAR16 *Cwd; 642 643 ProblemParam = NULL; 644 ShellStatus = SHELL_SUCCESS; 645 ParamCount = 0; 646 FileList = NULL; 647 648 // 649 // initialize the shell lib (we must be in non-auto-init...) 650 // 651 Status = ShellInitialize(); 652 ASSERT_EFI_ERROR(Status); 653 654 Status = CommandInit(); 655 ASSERT_EFI_ERROR(Status); 656 657 // 658 // parse the command line 659 // 660 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE); 661 if (EFI_ERROR(Status)) { 662 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) { 663 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"cp", ProblemParam); 664 FreePool(ProblemParam); 665 ShellStatus = SHELL_INVALID_PARAMETER; 666 } else { 667 ASSERT(FALSE); 668 } 669 } else { 670 // 671 // check for "-?" 672 // 673 if (ShellCommandLineGetFlag(Package, L"-?")) { 674 ASSERT(FALSE); 675 } 676 677 // 678 // Initialize SilentMode and RecursiveMode 679 // 680 if (gEfiShellProtocol->BatchIsActive()) { 681 SilentMode = TRUE; 682 } else { 683 SilentMode = ShellCommandLineGetFlag(Package, L"-q"); 684 } 685 RecursiveMode = ShellCommandLineGetFlag(Package, L"-r"); 686 687 switch (ParamCount = ShellCommandLineGetCount(Package)) { 688 case 0: 689 case 1: 690 // 691 // we have insufficient parameters 692 // 693 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel2HiiHandle, L"cp"); 694 ShellStatus = SHELL_INVALID_PARAMETER; 695 break; 696 case 2: 697 // 698 // must have valid CWD for single parameter... 699 // 700 Cwd = ShellGetCurrentDir(NULL); 701 if (Cwd == NULL){ 702 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"cp"); 703 ShellStatus = SHELL_INVALID_PARAMETER; 704 } else { 705 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, 1), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); 706 if (FileList == NULL || IsListEmpty(&FileList->Link) || EFI_ERROR(Status)) { 707 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, 1)); 708 ShellStatus = SHELL_NOT_FOUND; 709 } else { 710 ShellStatus = ProcessValidateAndCopyFiles(FileList, Cwd, SilentMode, RecursiveMode); 711 } 712 } 713 714 break; 715 default: 716 // 717 // Make a big list of all the files... 718 // 719 for (ParamCount--, LoopCounter = 1 ; LoopCounter < ParamCount && ShellStatus == SHELL_SUCCESS ; LoopCounter++) { 720 if (ShellGetExecutionBreakFlag()) { 721 break; 722 } 723 Status = ShellOpenFileMetaArg((CHAR16*)ShellCommandLineGetRawValue(Package, LoopCounter), EFI_FILE_MODE_WRITE|EFI_FILE_MODE_READ, &FileList); 724 if (EFI_ERROR(Status) || FileList == NULL || IsListEmpty(&FileList->Link)) { 725 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, LoopCounter)); 726 ShellStatus = SHELL_NOT_FOUND; 727 } 728 } 729 if (ShellStatus != SHELL_SUCCESS) { 730 Status = ShellCloseFileMetaArg(&FileList); 731 } else { 732 // 733 // now copy them all... 734 // 735 if (FileList != NULL && !IsListEmpty(&FileList->Link)) { 736 ShellStatus = ProcessValidateAndCopyFiles(FileList, PathCleanUpDirectories((CHAR16*)ShellCommandLineGetRawValue(Package, ParamCount)), SilentMode, RecursiveMode); 737 Status = ShellCloseFileMetaArg(&FileList); 738 if (EFI_ERROR(Status) && ShellStatus == SHELL_SUCCESS) { 739 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ERR_FILE), gShellLevel2HiiHandle, L"cp", ShellCommandLineGetRawValue(Package, ParamCount), ShellStatus|MAX_BIT); 740 ShellStatus = SHELL_ACCESS_DENIED; 741 } 742 } 743 } 744 break; 745 } // switch on parameter count 746 747 if (FileList != NULL) { 748 ShellCloseFileMetaArg(&FileList); 749 } 750 751 // 752 // free the command line package 753 // 754 ShellCommandLineFreeVarList (Package); 755 } 756 757 if (ShellGetExecutionBreakFlag()) { 758 return (SHELL_ABORTED); 759 } 760 761 return (ShellStatus); 762} 763 764