VirtualBox

Changeset 36973 in vbox


Ignore:
Timestamp:
May 5, 2011 4:44:10 PM (14 years ago)
Author:
vboxsync
Message:

VBoxManage/GuestCtrl: Update on copying and creating recursive directories/files.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageGuestCtrl.cpp

    r36887 r36973  
    4444#include <iprt/thread.h>
    4545
     46#include <map>
     47#include <vector>
     48
    4649#ifdef USE_XPCOM_QUEUE
    4750# include <sys/select.h>
     
    6669static volatile bool    g_fGuestCtrlCanceled = false;
    6770
    68 /*
    69  * Structure holding a directory entry.
    70  */
    71 typedef struct DIRECTORYENTRY
    72 {
    73     char       *pszSourcePath;
    74     char       *pszDestPath;
    75     RTLISTNODE  Node;
    76 } DIRECTORYENTRY, *PDIRECTORYENTRY;
     71typedef struct SOURCEFILEENTRY
     72{
     73    SOURCEFILEENTRY(const char *pszSource, const char *pszFilter)
     74                    : mSource(pszSource),
     75                      mFilter(pszFilter) {}
     76    SOURCEFILEENTRY(const char *pszSource)
     77                    : mSource(pszSource)
     78    {
     79        if (   !RTFileExists(pszSource)
     80            && !RTDirExists(pszSource))
     81        {
     82            /* No file and no directory -- maybe a filter? */
     83            if (NULL != strpbrk(RTPathFilename(pszSource), "*?"))
     84            {
     85                /* Yep, get the actual filter part. */
     86                mFilter = RTPathFilename(pszSource);
     87                /* Remove the filter from actual sourcec directory name. */
     88                RTPathStripFilename(mSource.mutableRaw());
     89                mSource.jolt();
     90            }
     91        }
     92    }
     93    Utf8Str mSource;
     94    Utf8Str mFilter;
     95} SOURCEFILEENTRY, *PSOURCEFILEENTRY;
     96typedef std::vector<SOURCEFILEENTRY> SOURCEVEC, *PSOURCEVEC;
     97
     98typedef struct DESTFILEENTRY
     99{
     100    DESTFILEENTRY(Utf8Str strFileName) : mFileName(strFileName) {}
     101    Utf8Str mFileName;
     102} DESTFILEENTRY, *PDESTFILEENTRY;
     103typedef std::map< Utf8Str, std::vector<DESTFILEENTRY> > DESTDIRMAP, *PDESTDIRMAP;
     104typedef std::map< Utf8Str, std::vector<DESTFILEENTRY> >::iterator DESTDIRMAPITER, *PDESTDIRMAPITER;
    77105
    78106/**
     
    491519
    492520            case GETOPTDEF_EXEC_WAITFORSTDERR:
    493                 fWaitForExit = (fOutputFlags |= ProcessOutputFlag_StdErr);
     521                fWaitForExit = (fOutputFlags |= ProcessOutputFlag_StdErr) ? true : false;
    494522                break;
    495523
     
    735763
    736764/**
    737  * Appends a new file/directory entry to a given list.
    738  *
    739  * @return  IPRT status code.
    740  * @param   pszFileSource       Full qualified source path of file to copy (optional).
    741  * @param   pszFileDest         Full qualified destination path (optional).
    742  * @param   pList               Copy list used for insertion.
    743  *
    744  * @todo    r=bird: Since everyone is maintaining an entry count, it would make
    745  *          sense to abstract the list. To simplify cleanup work, it would be
    746  *          preferable to use a standard C++ container template class.
    747  */
    748 static int ctrlDirectoryEntryAppend(const char *pszFileSource, const char *pszFileDest,
    749                                     PRTLISTNODE pList)
    750 {
    751     AssertPtrReturn(pList, VERR_INVALID_POINTER);
    752     AssertReturn(pszFileSource || pszFileDest, VERR_INVALID_PARAMETER);
    753 
    754     PDIRECTORYENTRY pNode = (PDIRECTORYENTRY)RTMemAlloc(sizeof(DIRECTORYENTRY));
    755     if (pNode == NULL)
    756         return VERR_NO_MEMORY;
    757 
    758     pNode->pszSourcePath = NULL;
    759     pNode->pszDestPath = NULL;
    760 
    761     if (pszFileSource)
    762     {
    763         pNode->pszSourcePath = RTStrDup(pszFileSource);
    764         AssertPtrReturn(pNode->pszSourcePath, VERR_NO_MEMORY);
    765     }
    766     if (pszFileDest)
    767     {
    768         pNode->pszDestPath = RTStrDup(pszFileDest);
    769         AssertPtrReturn(pNode->pszDestPath, VERR_NO_MEMORY);
    770     }
    771 
    772     pNode->Node.pPrev = NULL;
    773     pNode->Node.pNext = NULL;
    774     RTListAppend(pList, &pNode->Node);
    775     return VINF_SUCCESS;
    776 }
    777 
    778 /**
    779  * Destroys a directory list.
    780  *
    781  * @param   pList               Pointer to list to destroy.
    782  */
    783 static void ctrlDirectoryListDestroy(PRTLISTNODE pList)
    784 {
    785     AssertPtr(pList);
    786 
    787     /* Destroy file list. */
    788     PDIRECTORYENTRY pNode = RTListGetFirst(pList, DIRECTORYENTRY, Node);
    789     while (pNode)
    790     {
    791         PDIRECTORYENTRY pNext = RTListNodeGetNext(&pNode->Node, DIRECTORYENTRY, Node);
    792         bool fLast = RTListNodeIsLast(pList, &pNode->Node);
    793 
    794         if (pNode->pszSourcePath)
    795             RTStrFree(pNode->pszSourcePath);
    796         if (pNode->pszDestPath)
    797             RTStrFree(pNode->pszDestPath);
    798         RTListNodeRemove(&pNode->Node);
    799         RTMemFree(pNode);
    800 
    801         if (fLast)
    802             break;
    803 
    804         pNode = pNext;
    805     }
    806 }
    807 
    808 
    809 /**
    810765 * Reads a specified directory (recursively) based on the copy flags
    811766 * and appends all matching entries to the supplied list.
     
    821776 * @param   pcObjects           Where to store the overall objects to
    822777 *                              copy found.
    823  * @param   pList               Pointer to the object list to use.
     778 * @param   dirMap              Reference to destination directory map to store found
     779 *                              directories (primary key) + files (secondary key, vector).
    824780 */
    825781static int ctrlCopyDirectoryRead(const char *pszRootDir, const char *pszSubDir,
    826782                                 const char *pszFilter, const char *pszDest,
    827                                  uint32_t fFlags, uint32_t *pcObjects, PRTLISTNODE pList)
     783                                 uint32_t fFlags, uint32_t *pcObjects, DESTDIRMAP &dirMap)
    828784{
    829785    AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER);
     
    832788    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    833789    AssertPtrReturn(pcObjects, VERR_INVALID_POINTER);
    834     AssertPtrReturn(pList, VERR_INVALID_POINTER);
    835790
    836791    /*
     
    880835                        char *pszNewSub = NULL;
    881836                        if (pszSubDir)
    882                             RTStrAPrintf(&pszNewSub, "%s%s/", pszSubDir, DirEntry.szName);
     837                            RTStrAPrintf(&pszNewSub, "%s/%s", pszSubDir, DirEntry.szName);
    883838                        else
    884                             RTStrAPrintf(&pszNewSub, "%s/", DirEntry.szName);
     839                            RTStrAPrintf(&pszNewSub, "%s", DirEntry.szName);
    885840
    886841                        if (pszNewSub)
    887842                        {
     843                            dirMap[pszNewSub];
     844
    888845                            rc = ctrlCopyDirectoryRead(pszRootDir, pszNewSub,
    889846                                                       pszFilter, pszDest,
    890                                                        fFlags, pcObjects, pList);
     847                                                       fFlags, pcObjects, dirMap);
    891848                            RTStrFree(pszNewSub);
    892849                        }
     
    910867                        || RTStrSimplePatternMatch(pszFilter, DirEntry.szName))
    911868                    {
    912                         char *pszFileSource = NULL;
    913                         char *pszFileDest = NULL;
    914                         if (RTStrAPrintf(&pszFileSource, "%s%s%s",
    915                                          pszRootDir, pszSubDir ? pszSubDir : "",
    916                                          DirEntry.szName) >= 0)
    917                         {
    918                             if (RTStrAPrintf(&pszFileDest, "%s%s%s",
    919                                              pszDest, pszSubDir ? pszSubDir : "",
    920                                              DirEntry.szName) <= 0)
    921                             {
    922                                 rc = VERR_NO_MEMORY;
    923                             }
    924                         }
    925                         else
    926                             rc = VERR_NO_MEMORY;
    927 
    928                         if (RT_SUCCESS(rc))
    929                         {
    930                             rc = ctrlDirectoryEntryAppend(pszFileSource, pszFileDest, pList);
    931                             if (RT_SUCCESS(rc))
    932                                 *pcObjects += 1;
    933                         }
    934 
    935                         if (pszFileSource)
    936                             RTStrFree(pszFileSource);
    937                         if (pszFileDest)
    938                             RTStrFree(pszFileDest);
     869                        dirMap[pszSubDir].push_back(DESTFILEENTRY(Utf8Str(DirEntry.szName)));
     870                        *pcObjects += 1;
    939871                    }
    940872                }
     
    954886
    955887/**
    956  * Initializes the copy process and builds up an object list
    957  * with all required information to start the actual copy process.
     888 * Constructs a destinations map from a source entry and a destination root.
    958889 *
    959890 * @return  IPRT status code.
    960  * @param   pszSource           Source path on host to use.
    961  * @param   pszDest             Destination path on guest to use.
    962  * @param   fFlags              Copy flags.
    963  * @param   pcObjects           Where to store the count of objects to be copied.
    964  * @param   pList               Where to store the object list.
    965  */
    966 static int ctrlCopyInit(const char *pszSource, const char *pszDest, uint32_t fFlags,
    967                         uint32_t *pcObjects, PRTLISTNODE pList)
    968 {
    969     AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
    970     AssertPtrReturn(pszDest, VERR_INVALID_PARAMETER);
    971     AssertPtrReturn(pcObjects, VERR_INVALID_PARAMETER);
    972     AssertPtrReturn(pList, VERR_INVALID_PARAMETER);
    973 
     891 * @param   sourceEntry             Reference to a specified source entry to use.
     892 * @param   fFlags                  Copy file flags. Needed for recursive directory parsing.
     893 * @param   pszDestRoot             Pointer to destination root. This can be used to add one or
     894 *                                  more directories to the actual destination path.
     895 * @param   mapDest                 Reference to the destination map for storing the actual result.
     896 * @param   pcObjects               Pointer to a total object (file) count to copy.
     897 */
     898static int ctrlCopyConstructDestinations(SOURCEFILEENTRY &sourceEntry, uint32_t fFlags, const char *pszDestRoot,
     899                                         DESTDIRMAP &mapDest, uint32_t *pcObjects)
     900{
    974901    int rc = VINF_SUCCESS;
    975     char *pszSourceAbs = RTPathAbsDup(pszSource);
    976     if (pszSourceAbs)
    977     {
    978         if (   RTPathFilename(pszSourceAbs)
    979             && RTFileExists(pszSourceAbs)) /* We have a single file ... */
    980         {
    981             char *pszDestAbs = RTStrDup(pszDest);
    982             if (pszDestAbs)
    983             {
    984                 /* Do we have a trailing slash for the destination?
    985                  * Then this is a directory ... */
    986                 size_t cch = strlen(pszDestAbs);
    987                 if (    cch > 1
    988                     && (   RTPATH_IS_SLASH(pszDestAbs[cch - 1])
    989                         || RTPATH_IS_SLASH(pszDestAbs[cch - 2])
    990                        )
    991                    )
    992                 {
    993                     rc = RTStrAAppend(&pszDestAbs, RTPathFilename(pszSourceAbs));
    994                 }
    995                 else
    996                 {
    997                     /* Since the desetination seems not to be a directory,
    998                      * we assume that this is the absolute path to the destination
    999                      * file -> nothing to do here ... */
    1000                 }
    1001 
    1002                 if (RT_SUCCESS(rc))
    1003                 {
    1004                     rc = ctrlDirectoryEntryAppend(pszSourceAbs, pszDestAbs, pList);
    1005                     *pcObjects = 1;
    1006                 }
    1007                 RTStrFree(pszDestAbs);
    1008             }
    1009             else
    1010                 rc = VERR_NO_MEMORY;
    1011         }
    1012         else /* ... or a directory. */
    1013         {
    1014             /* Append trailing slash to absolute directory. */
    1015             if (RTDirExists(pszSourceAbs))
    1016                 RTStrAAppend(&pszSourceAbs, RTPATH_SLASH_STR);
    1017 
    1018             /* Extract directory filter (e.g. "*.exe"). */
    1019             char *pszFilter = RTPathFilename(pszSourceAbs);
    1020             char *pszSourceAbsRoot = RTStrDup(pszSourceAbs);
    1021             char *pszDestAbs = RTStrDup(pszDest);
    1022             if (   pszSourceAbsRoot
    1023                 && pszDestAbs)
    1024             {
    1025                 if (pszFilter)
    1026                 {
    1027                     RTPathStripFilename(pszSourceAbsRoot);
    1028                     rc = RTStrAAppend(&pszSourceAbsRoot, RTPATH_SLASH_STR);
    1029                 }
    1030                 else
    1031                 {
    1032                     /*
    1033                      * If we have more than one file to copy, make sure that we have
    1034                      * a trailing slash so that we can construct a full path name
    1035                      * (e.g. "foo.txt" -> "c:/foo/temp.txt") as destination.
    1036                      */
    1037                     size_t cch = strlen(pszSourceAbsRoot);
    1038                     if (    cch > 1
    1039                         &&  !RTPATH_IS_SLASH(pszSourceAbsRoot[cch - 1])
    1040                         &&  !RTPATH_IS_SLASH(pszSourceAbsRoot[cch - 2]))
    1041                     {
    1042                         rc = RTStrAAppend(&pszSourceAbsRoot, RTPATH_SLASH_STR);
    1043                     }
    1044                 }
    1045 
    1046                 if (RT_SUCCESS(rc))
    1047                 {
    1048                     /*
    1049                      * Make sure we have a valid destination path. All we can do
    1050                      * here is to check whether we have a trailing slash -- the rest
    1051                      * (i.e. path creation, rights etc.) needs to be done inside the guest.
    1052                      */
    1053                     size_t cch = strlen(pszDestAbs);
    1054                     if (    cch > 1
    1055                         &&  !RTPATH_IS_SLASH(pszDestAbs[cch - 1])
    1056                         &&  !RTPATH_IS_SLASH(pszDestAbs[cch - 2]))
    1057                     {
    1058                         rc = RTStrAAppend(&pszDestAbs, RTPATH_SLASH_STR);
    1059                     }
    1060                 }
    1061 
    1062                 if (RT_SUCCESS(rc))
    1063                 {
    1064                     rc = ctrlCopyDirectoryRead(pszSourceAbsRoot, NULL /* Sub directory */,
    1065                                                pszFilter, pszDestAbs,
    1066                                                fFlags, pcObjects, pList);
    1067                     if (RT_SUCCESS(rc) && *pcObjects == 0)
    1068                         rc = VERR_NOT_FOUND;
    1069                 }
    1070 
    1071                 if (pszDestAbs)
    1072                     RTStrFree(pszDestAbs);
    1073                 if (pszSourceAbsRoot)
    1074                     RTStrFree(pszSourceAbsRoot);
    1075             }
    1076             else
    1077                 rc = VERR_NO_MEMORY;
    1078         }
    1079         RTStrFree(pszSourceAbs);
     902    const char *pszSource = sourceEntry.mSource.c_str();
     903    if (   RTPathFilename(pszSource)
     904        && RTFileExists(pszSource))
     905    {
     906        /* Source is a single file. */
     907        char *pszFileName = RTPathFilename(pszSource);
     908        mapDest[Utf8Str(pszDestRoot)].push_back(DESTFILEENTRY(pszFileName));
     909
     910        *pcObjects++;
    1080911    }
    1081912    else
    1082         rc = VERR_NO_MEMORY;
     913    {
     914        /* Source is either a directory or a filter (e.g. *.dll). */
     915        rc = ctrlCopyDirectoryRead(pszSource,
     916                                   NULL /* pszSubDir */,
     917                                   sourceEntry.mFilter.isEmpty() ? NULL : sourceEntry.mFilter.c_str(),
     918                                   pszDestRoot, fFlags, pcObjects, mapDest);
     919    }
     920    return rc;
     921}
     922
     923/**
     924 * Determines the destination root for a specified source entry.
     925 *
     926 * @return  IPRT status code.
     927 * @param   ppszDestRoot                Receives pointer of allocated destination root.
     928 * @param   sourceEntry             Source entry to determine the destination root for.
     929 * @param   pszDest                 Original destination string to use.
     930 */
     931static int ctrlCopyGetDestinationRoot(char **ppszDestRoot, SOURCEFILEENTRY &sourceEntry, const char *pszDest)
     932{
     933    AssertPtrReturn(ppszDestRoot, VERR_INVALID_POINTER);
     934    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
     935
     936    int rc = VINF_SUCCESS;
     937
     938    /*
     939     * If a source filter is set (e.g. *.dll) use the original
     940     * destination as our final root, because we want to copy all filtered
     941     * files directly into the original root (and its sub directories if apply).
     942     */
     943    char *pszDestRoot;
     944    if (!sourceEntry.mFilter.isEmpty())
     945        pszDestRoot = RTStrDup(pszDest);
     946    else
     947    {
     948        /*
     949         * However, if no source filter is set we want to also copy the original
     950         * source directory to our destination so that source "c:\foo", dest "c:\temp"
     951         * becomes "c:\temp\foo".
     952         */
     953        int iLen = RTStrAPrintf(&pszDestRoot, "%s/%s",
     954                                pszDest, RTPathFilename(sourceEntry.mSource.c_str()));
     955        if (!iLen)
     956            rc = VERR_NO_MEMORY;
     957    }
     958
     959    if (RT_SUCCESS(rc))
     960        *ppszDestRoot = pszDestRoot;
     961    return rc;
     962}
     963
     964/**
     965 * Prepares the destination directory hirarchy on the guest side by creating the directories
     966 * and sets the appropriate access rights.
     967 *
     968 * @return  IPRT status code.
     969 * @param   pGuest                  IGuest interface pointer.
     970 * @param   itDest                  Destination map iterator to process.
     971 * @param   pszDestRoot             Destination root to use.
     972 * @param   pszUsername             Username to use.
     973 * @param   pszPassword             Password to use.
     974 */
     975static int ctrlCopyPrepareDestDirectory(IGuest *pGuest, DESTDIRMAPITER itDest, const char *pszDestRoot,
     976                                        const char *pszUsername, const char *pszPassword)
     977{
     978    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
     979    AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER);
     980    AssertPtrReturn(pszUsername, VERR_INVALID_POINTER);
     981    AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
     982
     983    ComPtr<IProgress> progress;
     984    char *pszDestFinal = NULL;
     985    int rc = VINF_SUCCESS;
     986
     987    /* Create root directory (= empty name) and skip the rest for
     988     * this round. */
     989    if (itDest->first.isEmpty())
     990    {
     991        pszDestFinal = RTStrDup(pszDestRoot);
     992        if (!pszDestFinal)
     993            rc = VERR_NO_MEMORY;
     994    }
     995    /* @todo Skip creating empty directories (or directories where a file filter (e.g. *.dll)
     996     * did not find any files to copy. Make this configurable later! */
     997    else if (itDest->second.size())
     998    {
     999        if (!RTStrAPrintf(&pszDestFinal, "%s/%s", pszDestRoot, itDest->first.c_str()))
     1000            rc = VERR_NO_MEMORY;
     1001    }
     1002
     1003    if (RT_SUCCESS(rc) && pszDestFinal)
     1004    {
     1005        HRESULT hrc = pGuest->CreateDirectory(Bstr(pszDestFinal).raw(),
     1006                                              Bstr(pszUsername).raw(), Bstr(pszPassword).raw(),
     1007                                              700, CreateDirectoryFlag_Parents, progress.asOutParam());
     1008        if (FAILED(hrc))
     1009            rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
     1010        RTStrFree(pszDestFinal);
     1011    }
    10831012    return rc;
    10841013}
     
    10881017 *
    10891018 * @return  IPRT status code.
    1090  * @param   pGuest          IGuest interface pointer.
    1091  * @param   fVerbose        Verbose flag.
    1092  * @param   pszSource       Source path of existing host file to copy.
    1093  * @param   pszDest         Destination path on guest to copy the file to.
    1094  * @param   pszUserName     User name on guest to use for the copy operation.
    1095  * @param   pszPassword     Password of user account.
    1096  * @param   fFlags          Copy flags.
    1097  */
    1098 static int ctrlCopyFileToGuest(IGuest *pGuest, bool fVerbose, const char *pszSource, const char *pszDest,
     1019 * @param   pGuest                  IGuest interface pointer.
     1020 * @param   pszSource               Source path of existing host file to copy.
     1021 * @param   pszDest                 Destination path on guest to copy the file to.
     1022 * @param   pszUserName             User name on guest to use for the copy operation.
     1023 * @param   pszPassword             Password of user account.
     1024 * @param   fFlags                  Copy flags.
     1025 */
     1026static int ctrlCopyFileToGuest(IGuest *pGuest, const char *pszSource, const char *pszDest,
    10991027                               const char *pszUserName, const char *pszPassword,
    11001028                               uint32_t fFlags)
    11011029{
    1102     AssertPtrReturn(pGuest, VERR_INVALID_PARAMETER);
    1103     AssertPtrReturn(pszSource, VERR_INVALID_PARAMETER);
    1104     AssertPtrReturn(pszDest, VERR_INVALID_PARAMETER);
    1105     AssertPtrReturn(pszUserName, VERR_INVALID_PARAMETER);
    1106     AssertPtrReturn(pszPassword, VERR_INVALID_PARAMETER);
     1030    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
     1031    AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
     1032    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
     1033    AssertPtrReturn(pszUserName, VERR_INVALID_POINTER);
     1034    AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
    11071035
    11081036    int vrc = VINF_SUCCESS;
     
    11221050}
    11231051
     1052
     1053static int ctrlCopyToDestDirectory(IGuest *pGuest, bool fVerbose, DESTDIRMAPITER itDest, const char *pszDestRoot,
     1054                                   SOURCEFILEENTRY &sourceEntry, uint32_t uFlags, const char *pszUsername, const char *pszPassword)
     1055{
     1056    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
     1057    AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER);
     1058    AssertPtrReturn(pszUsername, VERR_INVALID_POINTER);
     1059    AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
     1060
     1061    int rc = VINF_SUCCESS;
     1062    for (unsigned long l = 0; l < itDest->second.size(); l++)
     1063    {
     1064        int iLen;
     1065        char *pszSource;
     1066        if (itDest->first.isEmpty())
     1067            iLen = RTStrAPrintf(&pszSource, "%s/%s", sourceEntry.mSource.c_str(),
     1068                                itDest->second[l].mFileName.c_str());
     1069        else
     1070            iLen = RTStrAPrintf(&pszSource, "%s/%s/%s", sourceEntry.mSource.c_str(),
     1071                                itDest->first.c_str(), itDest->second[l].mFileName.c_str());
     1072        if (!iLen)
     1073        {
     1074            rc = VERR_NO_MEMORY;
     1075            break;
     1076        }
     1077
     1078        char *pszDest;
     1079        if (itDest->first.isEmpty())
     1080            iLen = RTStrAPrintf(&pszDest, "%s/%s", pszDestRoot,
     1081                                itDest->second[l].mFileName.c_str());
     1082        else
     1083            iLen = RTStrAPrintf(&pszDest, "%s/%s/%s", pszDestRoot, itDest->first.c_str(),
     1084                                itDest->second[l].mFileName.c_str());
     1085        if (!iLen)
     1086        {
     1087            rc = VERR_NO_MEMORY;
     1088            RTStrFree(pszSource);
     1089            break;
     1090        }
     1091
     1092        if (fVerbose)
     1093            RTPrintf("\"%s\" -> \"%s\"\n", pszSource, pszDest);
     1094
     1095        /* Finally copy the desired file (if no dry run selected). */
     1096        rc = ctrlCopyFileToGuest(pGuest, pszSource, pszDest,
     1097                                 pszUsername, pszPassword, uFlags);
     1098        RTStrFree(pszSource);
     1099        RTStrFree(pszDest);
     1100    }
     1101    return rc;
     1102}
     1103
    11241104static int handleCtrlCopyTo(ComPtr<IGuest> guest, HandlerArg *pArg)
    11251105{
     
    11671147    bool fDryRun = false;
    11681148
    1169     RTLISTNODE listSources;
    1170     uint32_t cSources = 0;
    1171     RTListInit(&listSources);
     1149    SOURCEVEC vecSources;
    11721150
    11731151    int vrc = VINF_SUCCESS;
     
    12171195                else
    12181196                {
    1219                     vrc = ctrlDirectoryEntryAppend(ValueUnion.psz,      /* Source */
    1220                                                    NULL,                /* No destination given */
    1221                                                    &listSources);
    1222                     if (RT_SUCCESS(vrc))
    1223                     {
    1224                         cSources++;
    1225                         if (cSources == UINT32_MAX)
    1226                             return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many sources specified! Aborting.");
    1227                     }
    1228                     else
    1229                         return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to append source: %Rrc", vrc);
     1197                    /* Save the source directory. */
     1198                    vecSources.push_back(SOURCEFILEENTRY(ValueUnion.psz));
    12301199                }
    12311200                break;
     
    12371206    }
    12381207
    1239     if (!cSources)
     1208    if (!vecSources.size())
    12401209        return errorSyntax(USAGE_GUESTCONTROL,
    12411210                           "No source(s) specified!");
     
    12501219
    12511220    /*
    1252      * Done parsing arguments, do stuff.
     1221     * Done parsing arguments, do some more preparations.
    12531222     */
    1254     HRESULT rc = S_OK;
    12551223    if (fVerbose)
    12561224    {
    12571225        if (fDryRun)
    12581226            RTPrintf("Dry run - no files copied!\n");
    1259         RTPrintf("Gathering file information ...\n");
    1260     }
    1261 
    1262     RTLISTNODE listToCopy;
    1263     RTListInit(&listToCopy);
    1264     uint32_t cTotalObjects = 0;
    1265 
    1266     PDIRECTORYENTRY pNodeSource;
    1267     RTListForEach(&listSources, pNodeSource, DIRECTORYENTRY, Node)
     1227    }
     1228
     1229    /* Strip traling slash from destination path. */
     1230    RTPathStripTrailingSlash(Utf8Dest.mutableRaw());
     1231    Utf8Dest.jolt();
     1232
     1233    /*
     1234     * Here starts the actual fun!
     1235     */
     1236    for (unsigned long s = 0; s < vecSources.size(); s++)
    12681237    {
    12691238        uint32_t cObjects = 0;
    1270         vrc = ctrlCopyInit(pNodeSource->pszSourcePath, Utf8Dest.c_str(), fFlags,
    1271                            &cObjects, &listToCopy);
    1272         if (RT_FAILURE(vrc))
    1273         {
    1274             switch (vrc)
     1239        DESTDIRMAP mapDest;
     1240
     1241        char *pszDestRoot;
     1242        vrc = ctrlCopyGetDestinationRoot(&pszDestRoot, vecSources[s], Utf8Dest.c_str());
     1243        if (RT_SUCCESS(vrc))
     1244        {
     1245            vrc = ctrlCopyConstructDestinations(vecSources[s], fFlags, pszDestRoot,
     1246                                                mapDest, &cObjects);
     1247            if (RT_FAILURE(vrc))
    12751248            {
    1276                 case VERR_NOT_FOUND:
    1277                     /* Not fatal, just continue to the next source entry (if available). */
    1278                     continue;
    1279 
    1280                 case VERR_FILE_NOT_FOUND:
    1281                     RTMsgError("Source path \"%s\" not found!\n", Utf8Source.c_str());
    1282                     break;
    1283 
    1284                 default:
    1285                     RTMsgError("Failed to initialize, rc=%Rrc\n", vrc);
    1286                     break;
     1249                if (   fVerbose
     1250                    && vrc == VERR_FILE_NOT_FOUND)
     1251                {
     1252                    RTPrintf("Warning: Source \"\%s\" does not exist, skipping!\n",
     1253                             vecSources[s].mSource.c_str());
     1254                }
    12871255            }
    1288         }
    1289         else if (fVerbose)
    1290         {
    1291             RTPrintf("Source \"%s\" has %ld elements to copy\n",
    1292                      pNodeSource->pszSourcePath, cObjects);
    1293         }
    1294         cTotalObjects += cObjects;
    1295     }
    1296 
    1297     if (fVerbose && cTotalObjects)
    1298         RTPrintf("Total %ld elements to copy to \"%s\"\n",
    1299                  cTotalObjects, Utf8Dest.c_str());
    1300 
    1301     if (cTotalObjects)
    1302     {
    1303         PDIRECTORYENTRY pNode;
    1304         uint32_t uCurObject = 1;
    1305 
    1306         RTListForEach(&listToCopy, pNode, DIRECTORYENTRY, Node)
    1307         {
    1308             if (fVerbose)
    1309                 RTPrintf("Copying \"%s\" to \"%s\" (%u/%u) ...\n",
    1310                          pNode->pszSourcePath, pNode->pszDestPath, uCurObject, cTotalObjects);
    1311             /* Finally copy the desired file (if no dry run selected). */
    1312             if (!fDryRun)
    1313                 vrc = ctrlCopyFileToGuest(guest, fVerbose, pNode->pszSourcePath, pNode->pszDestPath,
    1314                                           Utf8UserName.c_str(), Utf8Password.c_str(), fFlags);
    1315             if (RT_FAILURE(vrc))
    1316                 break;
    1317             uCurObject++;
    1318         }
    1319 
    1320         Assert(cTotalObjects >= uCurObject - 1);
    1321         if (cTotalObjects != uCurObject - 1)
    1322             RTPrintf("Warning: %u elements instead of %ld were copied!\n",
    1323                      uCurObject - 1, cTotalObjects);
    1324         else if (RT_SUCCESS(vrc) && fVerbose)
    1325             RTPrintf("Copy operation successful!\n");
    1326     }
    1327 
    1328     ctrlDirectoryListDestroy(&listToCopy);
    1329     ctrlDirectoryListDestroy(&listSources);
    1330 
    1331     if (RT_FAILURE(vrc))
    1332         rc = VBOX_E_IPRT_ERROR;
    1333     return SUCCEEDED(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     1256            else
     1257            {
     1258                /*
     1259                 * Prepare directory structure of each destination directory.
     1260                 */
     1261                DESTDIRMAPITER itDest;
     1262                ComPtr<IProgress> progress;
     1263                for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++)
     1264                {
     1265                    if (!fDryRun)
     1266                        vrc = ctrlCopyPrepareDestDirectory(guest, itDest, pszDestRoot,
     1267                                                           Utf8UserName.c_str(), Utf8Password.c_str());
     1268                    if (RT_FAILURE(vrc))
     1269                        break;
     1270                }
     1271
     1272                if (fVerbose)
     1273                {
     1274                    if (!cObjects)
     1275                        RTPrintf("Warning: Source \"%s\" has no (matching) files to copy, skipping!\n",
     1276                                 vecSources[s].mSource.c_str());
     1277                    else
     1278                        RTPrintf("Copying \"%s\" (%u files) ...\n",
     1279                                 vecSources[s].mSource.c_str(), cObjects);
     1280                }
     1281
     1282                /*
     1283                 * Copy files of each destination root directory to the guest.
     1284                 */
     1285                for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++)
     1286                {
     1287                    if (fVerbose && itDest->second.size())
     1288                    {
     1289                        if (itDest->first.isEmpty())
     1290                            RTPrintf("Copying %u files ...\n", itDest->second.size());
     1291                        else
     1292                            RTPrintf("Copying directory \"%s\" (%u files) ...\n",
     1293                                     itDest->first.c_str(), itDest->second.size());
     1294                    }
     1295
     1296                    if (!fDryRun)
     1297                        vrc = ctrlCopyToDestDirectory(guest, fVerbose, itDest, pszDestRoot,
     1298                                                      vecSources[s], fFlags, Utf8UserName.c_str(), Utf8Password.c_str());
     1299                    if (RT_FAILURE(vrc))
     1300                        break;
     1301                }
     1302            }
     1303            RTStrFree(pszDestRoot);
     1304        }
     1305    }
     1306
     1307    return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
    13341308}
    13351309
     
    13651339    bool fVerbose = false;
    13661340
    1367     RTLISTNODE listDirs;
    1368     uint32_t cDirs = 0;
    1369     RTListInit(&listDirs);
     1341    DESTDIRMAP mapDirs;
    13701342
    13711343    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     
    13981370            case VINF_GETOPT_NOT_OPTION:
    13991371            {
    1400                 int vrc = ctrlDirectoryEntryAppend(NULL,              /* No source given */
    1401                                                    ValueUnion.psz,    /* Destination */
    1402                                                    &listDirs);
    1403                 if (RT_SUCCESS(vrc))
    1404                 {
    1405                     cDirs++;
    1406                     if (cDirs == UINT32_MAX)
    1407                         rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "Too many directories specified! Aborting.");
    1408                 }
    1409                 else
    1410                     rcExit = RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to append directory: %Rrc", vrc);
     1372                mapDirs[ValueUnion.psz]; /* Add destination directory to map. */
    14111373                break;
    14121374            }
     
    14181380    }
    14191381
     1382    uint32_t cDirs = mapDirs.size();
    14201383    if (rcExit == RTEXITCODE_SUCCESS && !cDirs)
    14211384        rcExit = errorSyntax(USAGE_GUESTCONTROL, "No directory to create specified!");
     
    14301393         */
    14311394        HRESULT hrc = S_OK;
    1432         if (fVerbose && cDirs > 1)
     1395        if (fVerbose && cDirs)
    14331396            RTPrintf("Creating %u directories ...\n", cDirs);
    14341397
    1435         PDIRECTORYENTRY pNode;
    1436         RTListForEach(&listDirs, pNode, DIRECTORYENTRY, Node)
     1398        DESTDIRMAPITER it = mapDirs.begin();
     1399        while (it != mapDirs.end())
    14371400        {
    14381401            if (fVerbose)
    1439                 RTPrintf("Creating directory \"%s\" ...\n", pNode->pszDestPath);
     1402                RTPrintf("Creating directory \"%s\" ...\n", it->first.c_str());
    14401403
    14411404            ComPtr<IProgress> progress;
    1442             hrc = guest->CreateDirectory(Bstr(pNode->pszDestPath).raw(),
     1405            hrc = guest->CreateDirectory(Bstr(it->first).raw(),
    14431406                                         Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(),
    14441407                                         fDirMode, fFlags, progress.asOutParam());
    14451408            if (FAILED(hrc))
    14461409            {
    1447                 ctrlPrintError(guest, COM_IIDOF(IGuest)); /* (return code ignored, save original rc) */
     1410                ctrlPrintError(guest, COM_IIDOF(IGuest)); /* Return code ignored, save original rc. */
    14481411                break;
    14491412            }
    1450         }
     1413
     1414            it++;
     1415        }
     1416
    14511417        if (FAILED(hrc))
    14521418            rcExit = RTEXITCODE_FAILURE;
    14531419    }
    1454 
    1455     /*
    1456      * Clean up and return.
    1457      */
    1458     ctrlDirectoryListDestroy(&listDirs);
    14591420
    14601421    return rcExit;
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette