/** Validate and if successful copy all the files from the list into destination directory. @param[in] FileList The list of files to copy. @param[in] DestDir The directory to copy files to. @param[in] SilentMode TRUE to eliminate screen output. @param[in] RecursiveMode TRUE to copy directories. @retval SHELL_INVALID_PARAMETER A parameter was invalid. @retval SHELL_SUCCESS The operation was successful. **/ SHELL_STATUS EFIAPI ProcessValidateAndCopyFiles( IN EFI_SHELL_FILE_INFO *FileList, IN CONST CHAR16 *DestDir, IN BOOLEAN SilentMode, IN BOOLEAN RecursiveMode ) { SHELL_STATUS ShellStatus; EFI_SHELL_FILE_INFO *List; EFI_FILE_INFO *FileInfo; CHAR16 *FullName; List = NULL; FullName = NULL; FileInfo = NULL; ShellOpenFileMetaArg((CHAR16*)DestDir, EFI_FILE_MODE_READ, &List); if (List != NULL && List->Link.ForwardLink != List->Link.BackLink) { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_MARG_ERROR), gShellLevel2HiiHandle, DestDir); ShellStatus = SHELL_INVALID_PARAMETER; ShellCloseFileMetaArg(&List); } else if (List != NULL) { ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink) != NULL); ASSERT(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName != NULL); FileInfo = gEfiShellProtocol->GetFileInfo(((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->Handle); ASSERT(FileInfo != NULL); StrnCatGrow(&FullName, NULL, ((EFI_SHELL_FILE_INFO *)List->Link.ForwardLink)->FullName, 0); ShellCloseFileMetaArg(&List); if ((FileInfo->Attribute & EFI_FILE_READ_ONLY) == 0) { ShellStatus = ValidateAndCopyFiles(FileList, FullName, SilentMode, RecursiveMode, NULL); } else { ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CP_DEST_ERROR), gShellLevel2HiiHandle); ShellStatus = SHELL_ACCESS_DENIED; } } else { ShellCloseFileMetaArg(&List); ShellStatus = ValidateAndCopyFiles(FileList, DestDir, SilentMode, RecursiveMode, NULL); } SHELL_FREE_NON_NULL(FileInfo); SHELL_FREE_NON_NULL(FullName); return (ShellStatus); }
/** Function to Copy one file to another location If the destination exists the user will be prompted and the result put into *resp @param[in] Source pointer to source file name @param[in] Dest pointer to destination file name @param[out] Resp pointer to response from question. Pass back on looped calling @param[in] SilentMode whether to run in quiet mode or not @retval SHELL_SUCCESS The source file was copied to the destination **/ SHELL_STATUS EFIAPI CopySingleFile( IN CONST CHAR16 *Source, IN CONST CHAR16 *Dest, OUT VOID **Resp, IN BOOLEAN SilentMode ) { VOID *Response; UINTN ReadSize; SHELL_FILE_HANDLE SourceHandle; SHELL_FILE_HANDLE DestHandle; EFI_STATUS Status; VOID *Buffer; CHAR16 *TempName; UINTN Size; EFI_SHELL_FILE_INFO *List; SHELL_STATUS ShellStatus; UINT64 SourceFileSize; UINT64 DestFileSize; EFI_FILE_PROTOCOL *DestVolumeFP; EFI_FILE_SYSTEM_INFO *DestVolumeInfo; UINTN DestVolumeInfoSize; ASSERT(Resp != NULL); SourceHandle = NULL; DestHandle = NULL; Response = *Resp; List = NULL; DestVolumeInfo = NULL; ReadSize = PcdGet16(PcdShellFileOperationSize); // Why bother copying a file to itself if (StrCmp(Source, Dest) == 0) { return (SHELL_SUCCESS); } // // Open destination file without create // Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE, 0); // // close file // if (DestHandle != NULL) { ShellCloseFile(&DestHandle); DestHandle = NULL; } // // if the destination file existed check response and possibly prompt user // if (!EFI_ERROR(Status)) { if (Response == NULL && !SilentMode) { Status = ShellPromptForResponseHii(ShellPromptResponseTypeYesNoAllCancel, STRING_TOKEN (STR_GEN_DEST_EXIST_OVR), gShellLevel2HiiHandle, &Response); } // // possibly return based on response // if (!SilentMode) { switch (*(SHELL_PROMPT_RESPONSE*)Response) { case ShellPromptResponseNo: // // return success here so we dont stop the process // return (SHELL_SUCCESS); case ShellPromptResponseCancel: *Resp = Response; // // indicate to stop everything // return (SHELL_ABORTED); case ShellPromptResponseAll: *Resp = Response; case ShellPromptResponseYes: break; default: return SHELL_ABORTED; } } } if (ShellIsDirectory(Source) == EFI_SUCCESS) { Status = ShellCreateDirectory(Dest, &DestHandle); if (EFI_ERROR(Status)) { return (SHELL_ACCESS_DENIED); } // // Now copy all the files under the directory... // TempName = NULL; Size = 0; StrnCatGrow(&TempName, &Size, Source, 0); StrnCatGrow(&TempName, &Size, L"\\*", 0); if (TempName != NULL) { ShellOpenFileMetaArg((CHAR16*)TempName, EFI_FILE_MODE_READ, &List); *TempName = CHAR_NULL; StrnCatGrow(&TempName, &Size, Dest, 0); StrnCatGrow(&TempName, &Size, L"\\", 0); ShellStatus = ValidateAndCopyFiles(List, TempName, SilentMode, TRUE, Resp); ShellCloseFileMetaArg(&List); SHELL_FREE_NON_NULL(TempName); Size = 0; } } else { // // open file with create enabled // Status = ShellOpenFileByName(Dest, &DestHandle, EFI_FILE_MODE_READ|EFI_FILE_MODE_WRITE|EFI_FILE_MODE_CREATE, 0); if (EFI_ERROR(Status)) { return (SHELL_ACCESS_DENIED); } // // open source file // Status = ShellOpenFileByName(Source, &SourceHandle, EFI_FILE_MODE_READ, 0); ASSERT_EFI_ERROR(Status); // //get file size of source file and freespace available on destination volume // ShellGetFileSize(SourceHandle, &SourceFileSize); ShellGetFileSize(DestHandle, &DestFileSize); // //if the destination file already exists then it will be replaced, meaning the sourcefile effectively needs less storage space // if(DestFileSize < SourceFileSize){ SourceFileSize -= DestFileSize; } else { SourceFileSize = 0; } // //get the system volume info to check the free space // DestVolumeFP = ConvertShellHandleToEfiFileProtocol(DestHandle); DestVolumeInfo = NULL; DestVolumeInfoSize = 0; Status = DestVolumeFP->GetInfo( DestVolumeFP, &gEfiFileSystemInfoGuid, &DestVolumeInfoSize, DestVolumeInfo ); if (Status == EFI_BUFFER_TOO_SMALL) { DestVolumeInfo = AllocateZeroPool(DestVolumeInfoSize); Status = DestVolumeFP->GetInfo( DestVolumeFP, &gEfiFileSystemInfoGuid, &DestVolumeInfoSize, DestVolumeInfo ); } // //check if enough space available on destination drive to complete copy // if (DestVolumeInfo->FreeSpace < SourceFileSize) { // //not enough space on destination directory to copy file // SHELL_FREE_NON_NULL(DestVolumeInfo); ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_CPY_FAIL), gShellLevel2HiiHandle); return(SHELL_VOLUME_FULL); } else { // // copy data between files // Buffer = AllocateZeroPool(ReadSize); ASSERT(Buffer != NULL); while (ReadSize == PcdGet16(PcdShellFileOperationSize) && !EFI_ERROR(Status)) { Status = ShellReadFile(SourceHandle, &ReadSize, Buffer); Status = ShellWriteFile(DestHandle, &ReadSize, Buffer); } } SHELL_FREE_NON_NULL(DestVolumeInfo); } // // close files // if (DestHandle != NULL) { ShellCloseFile(&DestHandle); DestHandle = NULL; } if (SourceHandle != NULL) { ShellCloseFile(&SourceHandle); SourceHandle = NULL; } // // return // return (SHELL_SUCCESS); }