VirtualBox

Ignore:
Timestamp:
Jul 21, 2011 7:29:54 AM (14 years ago)
Author:
vboxsync
Message:

GuestCtrl: Update of copy from guest (work in progress).

File:
1 edited

Legend:

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

    r37761 r38085  
    6969static volatile bool    g_fGuestCtrlCanceled = false;
    7070
     71typedef struct COPYCONTEXT
     72{
     73    IGuest *pGuest;
     74    bool fVerbose;
     75    bool fHostToGuest;
     76    char *pszUsername;
     77    char *pszPassword;
     78} COPYCONTEXT, *PCOPYCONTEXT;
     79
    7180/**
    7281 * An entry for a source element, including an optional filter.
     
    100109
    101110/**
    102  * An entry for an element which needs to be copied to the guest.
     111 * An entry for an element which needs to be copied/created to/on the guest.
    103112 */
    104113typedef struct DESTFILEENTRY
     
    187196                 "                            [--timeout <msec>] [--unix2dos] [--verbose]\n"
    188197                 "                            [--wait-exit] [--wait-stdout] [--wait-stderr]\n"
    189                  //"                          [--output-format=<dos>|<unix>]\n"
    190                  "                            [--output-type=<binary>|<text>]\n"
    191198                 "                            [-- [<argument1>] ... [<argumentN>]]\n"
    192199                 /** @todo Add a "--" parameter (has to be last parameter) to directly execute
    193200                  *        stuff, e.g. "VBoxManage guestcontrol execute <VMName> --username <> ... -- /bin/rm -Rf /foo". */
    194201                 "\n"
    195 #if 0
    196202                 "                            copyfrom\n"
    197203                 "                            <source on guest> <destination on host>\n"
     
    199205                 "                            [--dryrun] [--follow] [--recursive] [--verbose]\n"
    200206                 "\n"
    201 #endif
    202207                 "                            copyto|cp\n"
    203208                 "                            <source on host> <destination on guest>\n"
     
    206211                 "\n"
    207212                 "                            createdir[ectory]|mkdir|md\n"
    208                  "                            <directory to create on guest>\n"
     213                 "                            <director[y|ies] to create on guest>\n"
    209214                 "                            --username <name> --password <password>\n"
    210215                 "                            [--parents] [--mode <mode>] [--verbose]\n"
     216                 "\n"
     217                 "                            stat\n"
     218                 "                            <file element(s) to check on guest>\n"
     219                 "                            --username <name> --password <password>\n"
     220                 "                            [--verbose]\n"
    211221                 "\n"
    212222                 "                            updateadditions\n"
     
    572582    if (Utf8UserName.isEmpty())
    573583        return errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
     584
     585    /* Any output conversion not supported yet! */
     586    if (eOutputType != OUTPUTTYPE_UNDEFINED)
     587        return errorSyntax(USAGE_GUESTCONTROL, "Output conversion not implemented yet!");
    574588
    575589    /*
     
    685699                        *        generic problem and the new VFS APIs will handle it more
    686700                        *        transparently. (requires writing dos2unix/unix2dos filters ofc) */
    687                         if (eOutputType != OUTPUTTYPE_UNDEFINED)
     701
     702                        /*
     703                         * If aOutputData is text data from the guest process' stdout or stderr,
     704                         * it has a platform dependent line ending. So standardize on
     705                         * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
     706                         * Windows. Otherwise we end up with CR/CR/LF on Windows.
     707                         */
     708                        ULONG cbOutputDataPrint = cbOutputData;
     709                        for (BYTE *s = aOutputData.raw(), *d = s;
     710                             s - aOutputData.raw() < (ssize_t)cbOutputData;
     711                             s++, d++)
    688712                        {
    689                             /*
    690                              * If aOutputData is text data from the guest process' stdout or stderr,
    691                              * it has a platform dependent line ending. So standardize on
    692                              * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
    693                              * Windows. Otherwise we end up with CR/CR/LF on Windows.
    694                              */
    695                             ULONG cbOutputDataPrint = cbOutputData;
    696                             for (BYTE *s = aOutputData.raw(), *d = s;
    697                                  s - aOutputData.raw() < (ssize_t)cbOutputData;
    698                                  s++, d++)
     713                            if (*s == '\r')
    699714                            {
    700                                 if (*s == '\r')
    701                                 {
    702                                     /* skip over CR, adjust destination */
    703                                     d--;
    704                                     cbOutputDataPrint--;
    705                                 }
    706                                 else if (s != d)
    707                                     *d = *s;
     715                                /* skip over CR, adjust destination */
     716                                d--;
     717                                cbOutputDataPrint--;
    708718                            }
    709                             RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
     719                            else if (s != d)
     720                                *d = *s;
    710721                        }
    711                         else /* Just dump all data as we got it ... */
    712                             RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputData);
     722                        RTStrmWrite(g_pStdOut, aOutputData.raw(), cbOutputDataPrint);
    713723                    }
    714724                }
     
    790800}
    791801
    792 /** @todo Clean up too long parameter list -> move guest specific stuff into own struct etc! */
    793 static int ctrlCopyDirectoryReadGuest(IGuest *pGuest,
    794                                       const char *pszUsername, const char *pszPassword,
    795                                       const char *pszRootDir, const char *pszSubDir,
    796                                       const char *pszFilter, const char *pszDest,
    797                                       uint32_t fFlags, uint32_t *pcObjects, DESTDIRMAP &dirMap)
    798 {
    799     AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER);
     802static int ctrlCopyContextCreate(IGuest *pGuest, bool fVerbose, bool fHostToGuest,
     803                                 const char *pszUsername, const char *pszPassword,
     804                                 PCOPYCONTEXT *ppContext)
     805{
     806    AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
     807    AssertPtrReturn(pszUsername, VERR_INVALID_POINTER);
     808    AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
     809
     810    PCOPYCONTEXT pContext = (PCOPYCONTEXT)RTMemAlloc(sizeof(COPYCONTEXT));
     811    AssertPtrReturn(pContext, VERR_NO_MEMORY);
     812    pContext->pGuest = pGuest;
     813    pContext->fVerbose = fVerbose;
     814    pContext->fHostToGuest = fHostToGuest;
     815
     816    pContext->pszUsername = RTStrDup(pszUsername);
     817    if (!pContext->pszUsername)
     818    {
     819        RTMemFree(pContext);
     820        return VERR_NO_MEMORY;
     821    }
     822
     823    pContext->pszPassword = RTStrDup(pszPassword);
     824    if (!pContext->pszPassword)
     825    {
     826        RTStrFree(pContext->pszUsername);
     827        RTMemFree(pContext);
     828        return VERR_NO_MEMORY;
     829    }
     830
     831    *ppContext = pContext;
     832
     833    return VINF_SUCCESS;
     834}
     835
     836static void ctrlCopyContextFree(PCOPYCONTEXT pContext)
     837{
     838    if (pContext)
     839    {
     840        RTStrFree(pContext->pszUsername);
     841        RTStrFree(pContext->pszPassword);
     842        RTMemFree(pContext);
     843    }
     844}
     845
     846/*
     847 * Source          Dest                 Translated
     848 * c:\foo.txt      c:\from_host         c:\from_host\foo.txt
     849 * c:\asdf\foo     c:\qwer              c:\qwer\foo
     850 * c:\bar\baz.txt  d:\users\            d:\users\baz.txt
     851 * c:\*.dll        e:\baz               e:\baz
     852 */
     853static int ctrlCopyTranslatePath(PCOPYCONTEXT pContext,
     854                                 const char *pszSourceRoot, const char *pszSource,
     855                                 const char *pszDest, char **ppszTranslated)
     856{
     857    AssertPtrReturn(pContext, VERR_INVALID_POINTER);
     858    AssertPtrReturn(pszSourceRoot, VERR_INVALID_POINTER);
     859    AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
     860    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
     861    AssertPtrReturn(ppszTranslated, VERR_INVALID_POINTER);
     862
     863    /* Source path must contain the source root! */
     864    if (!RTPathStartsWith(pszSource, pszSourceRoot))
     865        return VERR_INVALID_PARAMETER;
     866
     867    /* Construct the relative dest destination path by "subtracting" the
     868     * source from the source root, e.g.
     869     *
     870     * source root path = "e:\foo\", source = "e:\foo\bar"
     871     * dest = "d:\baz\"
     872     * translated = "d:\baz\bar\"
     873     */
     874
     875    size_t lenRoot = strlen(pszSourceRoot);
     876    AssertReturn(lenRoot, VERR_INVALID_PARAMETER);
     877    char *pszTranslated = RTStrDup(pszDest);
     878    AssertReturn(pszTranslated, VERR_NO_MEMORY);
     879    int vrc = RTStrAAppend(&pszTranslated, &pszSource[lenRoot]);
     880    if (RT_FAILURE(vrc))
     881        return vrc;
     882
     883    *ppszTranslated = pszTranslated;
     884
     885#ifdef DEBUG
     886    if (pContext->fVerbose)
     887        RTPrintf("Translating root=%s, source=%s, dest=%s -> %s\n",
     888                 pszSourceRoot, pszSource, pszDest, *ppszTranslated);
     889#endif
     890
     891    return vrc;
     892}
     893
     894static int ctrlCopyDirCreate(PCOPYCONTEXT pContext, const char *pszDir)
     895{
     896    AssertPtrReturn(pContext, VERR_INVALID_POINTER);
     897    AssertPtrReturn(pszDir, VERR_INVALID_POINTER);
     898
     899    int rc = VINF_SUCCESS;
     900    if (pContext->fHostToGuest) /* We want to create directories on the guest. */
     901    {
     902        HRESULT hrc = pContext->pGuest->DirectoryCreate(Bstr(pszDir).raw(),
     903                                                        Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(),
     904                                                        700, DirectoryCreateFlag_Parents);
     905        if (FAILED(hrc))
     906            rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
     907    }
     908    else /* ... or on the host. */
     909    {
     910        rc = RTDirCreate(pszDir, 700);
     911        if (rc == VERR_ALREADY_EXISTS)
     912            rc = VINF_SUCCESS;
     913    }
     914    return rc;
     915}
     916
     917static int ctrlCopyDirExists(PCOPYCONTEXT pContext, bool bGuest,
     918                             const char *pszDir, bool *fExists)
     919{
     920    AssertPtrReturn(pContext, false);
     921    AssertPtrReturn(pszDir, false);
     922    AssertPtrReturn(fExists, false);
     923
     924    int rc = VINF_SUCCESS;
     925    if (bGuest)
     926    {
     927        BOOL fDirExists = FALSE;
     928        HRESULT hr = pContext->pGuest->FileExists(Bstr(pszDir).raw(),
     929                                                  Bstr(pContext->pszUsername).raw(),
     930                                                  Bstr(pContext->pszPassword).raw(), &fDirExists);
     931        if (FAILED(hr))
     932            rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
     933        else
     934            *fExists = fDirExists ? true : false;
     935    }
     936    else
     937        *fExists = RTDirExists(pszDir);
     938    return rc;
     939}
     940
     941static int ctrlCopyDirExistsOnDest(PCOPYCONTEXT pContext, const char *pszDir,
     942                                   bool *fExists)
     943{
     944    return ctrlCopyDirExists(pContext, pContext->fHostToGuest,
     945                             pszDir, fExists);
     946}
     947
     948static int ctrlCopyDirExistsOnSource(PCOPYCONTEXT pContext, const char *pszDir,
     949                                     bool *fExists)
     950{
     951    return ctrlCopyDirExists(pContext, !pContext->fHostToGuest,
     952                             pszDir, fExists);
     953}
     954
     955static int ctrlCopyFileExists(PCOPYCONTEXT pContext, bool bOnGuest,
     956                              const char *pszFile, bool *fExists)
     957{
     958    AssertPtrReturn(pContext, false);
     959    AssertPtrReturn(pszFile, false);
     960    AssertPtrReturn(fExists, false);
     961
     962    int rc = VINF_SUCCESS;
     963    if (bOnGuest)
     964    {
     965        BOOL fFileExists = FALSE;
     966        HRESULT hr = pContext->pGuest->FileExists(Bstr(pszFile).raw(),
     967                                                  Bstr(pContext->pszUsername).raw(),
     968                                                  Bstr(pContext->pszPassword).raw(), &fFileExists);
     969        if (FAILED(hr))
     970            rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
     971        else
     972            *fExists = fFileExists ? true : false;
     973    }
     974    else
     975        *fExists = RTFileExists(pszFile);
     976    return rc;
     977}
     978
     979static int ctrlCopyFileExistsOnDest(PCOPYCONTEXT pContext, const char *pszFile,
     980                                    bool *fExists)
     981{
     982    return ctrlCopyFileExists(pContext, pContext->fHostToGuest,
     983                              pszFile, fExists);
     984}
     985
     986static int ctrlCopyFileExistsOnSource(PCOPYCONTEXT pContext, const char *pszFile,
     987                                      bool *fExists)
     988{
     989    return ctrlCopyFileExists(pContext, !pContext->fHostToGuest,
     990                              pszFile, fExists);
     991}
     992
     993static int ctrlCopyFileToTarget(PCOPYCONTEXT pContext, const char *pszFileSource,
     994                                const char *pszFileDest, uint32_t fFlags)
     995{
     996    AssertPtrReturn(pContext, VERR_INVALID_POINTER);
     997    AssertPtrReturn(pszFileSource, VERR_INVALID_POINTER);
     998    AssertPtrReturn(pszFileDest, VERR_INVALID_POINTER);
     999
     1000    if (pContext->fVerbose)
     1001    {
     1002        RTPrintf("Copying \"%s\" to \"%s\" ...\n",
     1003                 pszFileSource, pszFileDest);
     1004    }
     1005
     1006    int vrc = VINF_SUCCESS;
     1007    ComPtr<IProgress> progress;
     1008    HRESULT hr;
     1009    if (pContext->fHostToGuest)
     1010    {
     1011        hr = pContext->pGuest->CopyToGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
     1012                                           Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(),
     1013                                           fFlags, progress.asOutParam());
     1014    }
     1015    else
     1016    {
     1017        hr = pContext->pGuest->CopyFromGuest(Bstr(pszFileSource).raw(), Bstr(pszFileDest).raw(),
     1018                                             Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(),
     1019                                             fFlags, progress.asOutParam());
     1020    }
     1021
     1022    if (FAILED(hr))
     1023        vrc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
     1024    else
     1025    {
     1026        hr = showProgress(progress);
     1027        if (FAILED(hr))
     1028            vrc = ctrlPrintProgressError(progress);
     1029    }
     1030
     1031    return vrc;
     1032}
     1033
     1034static int ctrlCopyDirToGuest(PCOPYCONTEXT pContext,
     1035                              const char *pszSource, const char *pszFilter,
     1036                              const char *pszDest, uint32_t fFlags,
     1037                              const char *pszSubDir /* For recursion */)
     1038{
     1039    AssertPtrReturn(pContext, VERR_INVALID_POINTER);
     1040    AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
     1041    /* Filter is optional. */
     1042    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    8001043    /* Sub directory is optional. */
    801     /* Filter directory is optional. */
    802     AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    803     AssertPtrReturn(pcObjects, VERR_INVALID_POINTER);
    8041044
    8051045    /*
     
    8071047     */
    8081048    char szCurDir[RTPATH_MAX];
    809     int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszRootDir);
    810     if (RT_SUCCESS(rc) && pszSubDir != NULL)
     1049    int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource);
     1050    if (RT_SUCCESS(rc) && pszSubDir)
    8111051        rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);
    8121052
    813     if (RT_SUCCESS(rc))
    814     {
    815         ULONG uDirHandle;
    816         HRESULT hr = pGuest->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(), fFlags,
    817                                            Bstr(pszUsername).raw(), Bstr(pszPassword).raw(), &uDirHandle);
    818         if (FAILED(hr))
    819             rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    820         else
    821         {
    822             ComPtr <IGuestDirEntry> dirEntry;
    823             while (SUCCEEDED(hr = pGuest->DirectoryRead(uDirHandle, dirEntry.asOutParam())))
    824             {
    825                 GuestDirEntryType_T enmType;
    826                 dirEntry->COMGETTER(Type)(&enmType);
    827 
    828                 Bstr strName;
    829                 dirEntry->COMGETTER(Name)(strName.asOutParam());
    830 
    831                 switch (enmType)
    832                 {
    833                     case GuestDirEntryType_Directory:
    834                     {
    835                         /* Skip "." and ".." entries. */
    836                         if (   !strName.compare(Bstr("."))
    837                             || !strName.compare(Bstr("..")))
    838                             break;
    839 
    840                         const char *pszName = Utf8Str(strName).c_str();
    841                         if (fFlags & CopyFileFlag_Recursive)
    842                         {
    843                             char *pszNewSub = NULL;
    844                             if (pszSubDir)
    845                                 RTStrAPrintf(&pszNewSub, "%s/%s", pszSubDir, pszName);
    846                             else
    847                                 RTStrAPrintf(&pszNewSub, "%s", pszName);
    848 
    849                             if (pszNewSub)
    850                             {
    851                                 dirMap[pszNewSub];
    852 
    853                                 rc = ctrlCopyDirectoryReadGuest(pGuest, pszUsername, pszPassword,
    854                                                                 pszRootDir, pszNewSub,
    855                                                                 pszFilter, pszDest,
    856                                                                 fFlags, pcObjects, dirMap);
    857                                 RTStrFree(pszNewSub);
    858                             }
    859                             else
    860                                 rc = VERR_NO_MEMORY;
    861                         }
    862                         break;
    863                     }
    864 
    865                     case GuestDirEntryType_Symlink:
    866                         if (   (fFlags & CopyFileFlag_Recursive)
    867                             && (fFlags & CopyFileFlag_FollowLinks))
    868                         {
    869                             /* Fall through to next case is intentional. */
    870                         }
    871                         else
    872                             break;
    873 
    874                     case GuestDirEntryType_File:
    875                     {
    876                         const char *pszName = Utf8Str(strName).c_str();
    877                         if (   !pszFilter
    878                             || RTStrSimplePatternMatch(pszFilter, pszName))
    879                         {
    880                             dirMap[pszSubDir].push_back(DESTFILEENTRY(pszName));
    881                             *pcObjects += 1;
    882                         }
    883                         break;
    884                     }
    885 
    886                     default:
    887                         break;
    888                 }
    889             }
    890 
    891             hr = pGuest->DirectoryClose(uDirHandle);
    892             if (FAILED(rc))
    893                 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    894         }
    895     }
    896     return rc;
    897 }
    898 
    899 /**
    900  * Reads a specified directory (recursively) based on the copy flags
    901  * and appends all matching entries to the supplied list.
    902  *
    903  * @return  IPRT status code.
    904  * @param   pszRootDir          Directory to start with. Must end with
    905  *                              a trailing slash and must be absolute.
    906  * @param   pszSubDir           Sub directory part relative to the root
    907  *                              directory; needed for recursion.
    908  * @param   pszFilter           Search filter (e.g. *.pdf).
    909  * @param   pszDest             Destination directory.
    910  * @param   fFlags              Copy flags.
    911  * @param   pcObjects           Where to store the overall objects to
    912  *                              copy found.
    913  * @param   dirMap              Reference to destination directory map to store found
    914  *                              directories (primary key) + files (secondary key, vector).
    915  */
    916 static int ctrlCopyDirectoryReadHost(const char *pszRootDir, const char *pszSubDir,
    917                                      const char *pszFilter, const char *pszDest,
    918                                      uint32_t fFlags, uint32_t *pcObjects, DESTDIRMAP &dirMap)
    919 {
    920     AssertPtrReturn(pszRootDir, VERR_INVALID_POINTER);
    921     /* Sub directory is optional. */
    922     /* Filter directory is optional. */
    923     AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    924     AssertPtrReturn(pcObjects, VERR_INVALID_POINTER);
    925 
    926     /*
    927      * Construct current path.
    928      */
    929     char szCurDir[RTPATH_MAX];
    930     int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszRootDir);
    931     if (RT_SUCCESS(rc) && pszSubDir != NULL)
    932         rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);
     1053    /* Flag indicating whether the current directory was created on the
     1054     * target or not. */
     1055    bool fDirCreated = false;
    9331056
    9341057    /*
     
    9771100                        if (pszNewSub)
    9781101                        {
    979                             dirMap[pszNewSub];
    980 
    981                             rc = ctrlCopyDirectoryReadHost(pszRootDir, pszNewSub,
    982                                                            pszFilter, pszDest,
    983                                                            fFlags, pcObjects, dirMap);
     1102                            rc = ctrlCopyDirToGuest(pContext,
     1103                                                    pszSource, pszFilter,
     1104                                                    pszDest, fFlags, pszNewSub);
    9841105                            RTStrFree(pszNewSub);
    9851106                        }
     
    10041125                        || RTStrSimplePatternMatch(pszFilter, DirEntry.szName))
    10051126                    {
    1006                         dirMap[pszSubDir].push_back(DESTFILEENTRY(Utf8Str(DirEntry.szName)));
    1007                         *pcObjects += 1;
     1127                        if (!fDirCreated)
     1128                        {
     1129                            char *pszDestDir;
     1130                            rc = ctrlCopyTranslatePath(pContext, pszSource, szCurDir,
     1131                                                       pszDest, &pszDestDir);
     1132                            if (RT_SUCCESS(rc))
     1133                            {
     1134                                rc = ctrlCopyDirCreate(pContext, pszDestDir);
     1135                                RTStrFree(pszDestDir);
     1136
     1137                                fDirCreated = true;
     1138                            }
     1139                        }
     1140
     1141                        if (RT_SUCCESS(rc))
     1142                        {
     1143                            char *pszFileSource;
     1144                            if (RTStrAPrintf(&pszFileSource, "%s/%s",
     1145                                             szCurDir, DirEntry.szName))
     1146                            {
     1147                                char *pszFileDest;
     1148                                rc = ctrlCopyTranslatePath(pContext, pszSource, pszFileSource,
     1149                                                           pszDest, &pszFileDest);
     1150                                if (RT_SUCCESS(rc))
     1151                                {
     1152                                    rc = ctrlCopyFileToTarget(pContext, pszFileSource,
     1153                                                              pszFileDest, 0 /* Flags? */);
     1154                                    RTStrFree(pszFileDest);
     1155                                }
     1156                                RTStrFree(pszFileSource);
     1157                            }
     1158                        }
    10081159                    }
    10091160                    break;
     
    10221173}
    10231174
    1024 /**
    1025  * Constructs a destinations map from a source entry and a destination root.
    1026  *
    1027  * @return  IPRT status code.
    1028  * @param   fHostToGuest
    1029  * @param   sourceEntry             Reference to a specified source entry to use.
    1030  * @param   fFlags                  Copy file flags. Needed for recursive directory parsing.
    1031  * @param   pszDestRoot             Pointer to destination root. This can be used to add one or
    1032  *                                  more directories to the actual destination path.
    1033  * @param   mapDest                 Reference to the destination map for storing the actual result.
    1034  * @param   pcObjects               Pointer to a total object (file) count to copy.
    1035  */
    1036 static int ctrlCopyConstructDestinationsForGuest(SOURCEFILEENTRY &sourceEntry, uint32_t fFlags,
    1037                                                  const char *pszDestRoot, DESTDIRMAP &mapDest,
    1038                                                  uint32_t *pcObjects)
    1039 {
    1040     int rc = VINF_SUCCESS;
    1041     const char *pszSource = sourceEntry.mSource.c_str();
    1042 
    1043     if (   RTPathFilename(pszSource)
    1044         && RTFileExists(pszSource))
    1045     {
    1046         /* Source is a single file. */
    1047         char *pszFileName = RTPathFilename(pszSource);
    1048         mapDest[Utf8Str("")].push_back(DESTFILEENTRY(pszFileName));
    1049 
    1050         *pcObjects += 1;
    1051     }
     1175static int ctrlCopyDirToHost(PCOPYCONTEXT pContext,
     1176                             const char *pszSource, const char *pszFilter,
     1177                             const char *pszDest, uint32_t fFlags,
     1178                             const char *pszSubDir /* For recursion */)
     1179{
     1180    AssertPtrReturn(pContext, VERR_INVALID_POINTER);
     1181    AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
     1182    /* Filter is optional. */
     1183    AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
     1184    /* Sub directory is optional. */
     1185
     1186    /*
     1187     * Construct current path.
     1188     */
     1189    char szCurDir[RTPATH_MAX];
     1190    int rc = RTStrCopy(szCurDir, sizeof(szCurDir), pszSource);
     1191    if (RT_SUCCESS(rc) && pszSubDir)
     1192        rc = RTPathAppend(szCurDir, sizeof(szCurDir), pszSubDir);
     1193
     1194    /* Flag indicating whether the current directory was created on the
     1195     * target or not. */
     1196    bool fDirCreated = false;
     1197
     1198    ULONG uDirHandle;
     1199    HRESULT hr = pContext->pGuest->DirectoryOpen(Bstr(szCurDir).raw(), Bstr(pszFilter).raw(),
     1200                                                 fFlags,
     1201                                                 Bstr(pContext->pszUsername).raw(), Bstr(pContext->pszPassword).raw(),
     1202                                                 &uDirHandle);
     1203    if (FAILED(hr))
     1204        rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
    10521205    else
    10531206    {
    1054         /* Source is either a directory or a filter (e.g. *.dll). */
    1055         rc = ctrlCopyDirectoryReadHost(pszSource,
    1056                                        NULL /* pszSubDir */,
    1057                                        sourceEntry.mFilter.isEmpty() ? NULL : sourceEntry.mFilter.c_str(),
    1058                                        pszDestRoot, fFlags, pcObjects, mapDest);
    1059     }
     1207        ComPtr <IGuestDirEntry> dirEntry;
     1208        while (SUCCEEDED(hr = pContext->pGuest->DirectoryRead(uDirHandle, dirEntry.asOutParam())))
     1209        {
     1210            GuestDirEntryType_T enmType;
     1211            dirEntry->COMGETTER(Type)(&enmType);
     1212
     1213            Bstr strName;
     1214            dirEntry->COMGETTER(Name)(strName.asOutParam());
     1215
     1216            switch (enmType)
     1217            {
     1218                case GuestDirEntryType_Directory:
     1219                {
     1220                    /* Skip "." and ".." entries. */
     1221                    if (   !strName.compare(Bstr("."))
     1222                        || !strName.compare(Bstr("..")))
     1223                        break;
     1224
     1225                    if (fFlags & CopyFileFlag_Recursive)
     1226                    {
     1227                        Utf8Str strDir(strName);
     1228                        char *pszNewSub = NULL;
     1229                        if (pszSubDir)
     1230                            RTStrAPrintf(&pszNewSub, "%s/%s", pszSubDir, strDir.c_str());
     1231                        else
     1232                            RTStrAPrintf(&pszNewSub, "%s", strDir.c_str());
     1233
     1234                        if (pszNewSub)
     1235                        {
     1236                            rc = ctrlCopyDirToHost(pContext,
     1237                                                   pszSource, pszFilter,
     1238                                                   pszDest, fFlags, pszNewSub);
     1239                            RTStrFree(pszNewSub);
     1240                        }
     1241                        else
     1242                            rc = VERR_NO_MEMORY;
     1243                    }
     1244                    break;
     1245                }
     1246
     1247                case GuestDirEntryType_Symlink:
     1248                    if (   (fFlags & CopyFileFlag_Recursive)
     1249                        && (fFlags & CopyFileFlag_FollowLinks))
     1250                    {
     1251                        /* Fall through to next case is intentional. */
     1252                    }
     1253                    else
     1254                        break;
     1255
     1256                case GuestDirEntryType_File:
     1257                {
     1258                    const char *pszName = Utf8Str(strName).c_str();
     1259                    if (   !pszFilter
     1260                        || RTStrSimplePatternMatch(pszFilter, pszName))
     1261                    {
     1262                        if (!fDirCreated)
     1263                        {
     1264                            char *pszDestDir;
     1265                            rc = ctrlCopyTranslatePath(pContext, pszSource, szCurDir,
     1266                                                       pszDest, &pszDestDir);
     1267                            if (RT_SUCCESS(rc))
     1268                            {
     1269                                rc = ctrlCopyDirCreate(pContext, pszDestDir);
     1270                                RTStrFree(pszDestDir);
     1271
     1272                                fDirCreated = true;
     1273                            }
     1274                        }
     1275
     1276                        if (RT_SUCCESS(rc))
     1277                        {
     1278                            Utf8Str strDir(strName);
     1279                            char *pszFileSource;
     1280                            if (RTStrAPrintf(&pszFileSource, "%s/%s",
     1281                                             szCurDir, strDir.c_str()))
     1282                            {
     1283                                char *pszFileDest;
     1284                                rc = ctrlCopyTranslatePath(pContext, pszSource, pszFileSource,
     1285                                                           pszDest, &pszFileDest);
     1286                                if (RT_SUCCESS(rc))
     1287                                {
     1288                                    rc = ctrlCopyFileToTarget(pContext, pszFileSource,
     1289                                                              pszFileDest, 0 /* Flags? */);
     1290                                    RTStrFree(pszFileDest);
     1291                                }
     1292                                RTStrFree(pszFileSource);
     1293                            }
     1294                        }
     1295                    }
     1296                    break;
     1297                }
     1298
     1299                default:
     1300                    break;
     1301            }
     1302        }
     1303
     1304        hr = pContext->pGuest->DirectoryClose(uDirHandle);
     1305        if (FAILED(rc))
     1306            rc = ctrlPrintError(pContext->pGuest, COM_IIDOF(IGuest));
     1307    }
     1308
    10601309    return rc;
    10611310}
    10621311
    1063 static int ctrlCopyConstructDestinationsForHost(IGuest *pGuest,
    1064                                                 const char *pszUsername, const char *pszPassword,
    1065                                                 SOURCEFILEENTRY &sourceEntry, uint32_t fFlags,
    1066                                                 const char *pszDestRoot, DESTDIRMAP &mapDest,
    1067                                                 uint32_t *pcObjects)
    1068 {
    1069     int rc = VINF_SUCCESS;
    1070     const char *pszSource = sourceEntry.mSource.c_str();
    1071 
    1072     BOOL fExists = FALSE;
    1073     HRESULT hr = pGuest->FileExists(Bstr(pszSource).raw(),
    1074                                     Bstr(pszUsername).raw(), Bstr(pszPassword).raw(), &fExists);
    1075     if (FAILED(rc))
    1076         rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
     1312static int ctrlCopyDirToTarget(PCOPYCONTEXT pContext,
     1313                               const char *pszSource, const char *pszFilter,
     1314                               const char *pszDest, uint32_t fFlags,
     1315                               const char *pszSubDir /* For recursion */)
     1316{
     1317    if (pContext->fHostToGuest)
     1318        return ctrlCopyDirToGuest(pContext, pszSource, pszFilter,
     1319                                  pszDest, fFlags, pszSubDir);
     1320    return ctrlCopyDirToHost(pContext, pszSource, pszFilter,
     1321                             pszDest, fFlags, pszSubDir);
     1322}
     1323
     1324static int ctrlCopyCreateSourceRoot(const char *pszSource, char **ppszSourceRoot)
     1325{
     1326    AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
     1327    AssertPtrReturn(ppszSourceRoot, VERR_INVALID_POINTER);
     1328
     1329    char *pszNewRoot = RTStrDup(pszSource);
     1330    AssertPtrReturn(pszNewRoot, VERR_NO_MEMORY);
     1331
     1332    size_t lenRoot = strlen(pszNewRoot);
     1333    if (   lenRoot
     1334        && pszNewRoot[lenRoot - 1] == '/'
     1335        && pszNewRoot[lenRoot - 1] == '\\'
     1336        && lenRoot > 1
     1337        && pszNewRoot[lenRoot - 2] == '/'
     1338        && pszNewRoot[lenRoot - 2] == '\\')
     1339    {
     1340        *ppszSourceRoot = pszNewRoot;
     1341        if (lenRoot > 1)
     1342            *ppszSourceRoot[lenRoot - 2] = '\0';
     1343        *ppszSourceRoot[lenRoot - 1] = '\0';
     1344    }
    10771345    else
    10781346    {
    1079         if (fExists)
    1080         {
    1081             /* Source is a single file. */
    1082             char *pszFileName = RTPathFilename(pszSource);
    1083             mapDest[Utf8Str(pszDestRoot)].push_back(DESTFILEENTRY(pszFileName));
    1084 
    1085             *pcObjects++;
    1086         }
    1087         else
    1088         {
    1089             /* Source is either a directory or a filter (e.g. *.dll). */
    1090             rc = ctrlCopyDirectoryReadGuest(pGuest, pszUsername, pszPassword,
    1091                                             pszSource, NULL /* pszSubDir */,
    1092                                             sourceEntry.mFilter.isEmpty() ? NULL : sourceEntry.mFilter.c_str(),
    1093                                             pszDestRoot, fFlags, pcObjects, mapDest);
    1094         }
    1095     }
    1096     return rc;
    1097 }
    1098 
    1099 /**
    1100  * Prepares the destination directory hirarchy on the guest side by creating the directories
    1101  * and sets the appropriate access rights.
    1102  *
    1103  * @return  IPRT status code.
    1104  * @param   pGuest                  IGuest interface pointer.
    1105  * @param   fHostToGuest
    1106  * @param   itDest                  Destination map iterator to process.
    1107  * @param   pszDestRoot             Destination root to use.
    1108  * @param   pszUsername             Username to use.
    1109  * @param   pszPassword             Password to use.
    1110  */
    1111 static int ctrlCopyPrepareDestDirectory(IGuest *pGuest, bool fHostToGuest,
    1112                                         const char *pszDestRoot, const char *pszDestSub,
    1113                                         const char *pszUsername, const char *pszPassword)
    1114 {
    1115     AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
    1116     AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER);
    1117     AssertPtrReturn(pszDestSub, VERR_INVALID_POINTER);
    1118     AssertPtrReturn(pszUsername, VERR_INVALID_POINTER);
    1119     AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
    1120 
    1121     char *pszDestFinal = NULL;
    1122     int rc = VINF_SUCCESS;
    1123 
    1124     /* Create root directory (= empty name) and skip the rest for
    1125      * this round. */
    1126     if (!strlen(pszDestSub))
    1127     {
    1128         pszDestFinal = RTStrDup(pszDestRoot);
    1129         if (!pszDestFinal)
    1130             rc = VERR_NO_MEMORY;
    1131     }
    1132     else /* Create sub-directories, also empty ones. */
    1133     {
    1134         if (!RTStrAPrintf(&pszDestFinal, "%s/%s", pszDestRoot, pszDestSub))
    1135             rc = VERR_NO_MEMORY;
    1136     }
    1137 
    1138     if (RT_SUCCESS(rc) && pszDestFinal)
    1139     {
    1140         if (fHostToGuest) /* We want to create directories on the guest. */
    1141         {
    1142             HRESULT hrc = pGuest->DirectoryCreate(Bstr(pszDestFinal).raw(),
    1143                                                   Bstr(pszUsername).raw(), Bstr(pszPassword).raw(),
    1144                                                   700, DirectoryCreateFlag_Parents);
    1145             if (FAILED(hrc))
    1146                 rc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    1147         }
    1148         else /* ... or on the host. */
    1149         {
    1150             rc = RTDirCreate(pszDestFinal, 700);
    1151         }
    1152         RTStrFree(pszDestFinal);
    1153     }
    1154     return rc;
    1155 }
    1156 
    1157 /**
    1158  * Copys a file from host to the guest.
    1159  *
    1160  * @return  IPRT status code.
    1161  * @param   pGuest                  IGuest interface pointer.
    1162  * @param   pszSource               Source path of existing host file to copy to the guest.
    1163  * @param   pszDest                 Destination path on guest to copy the file to.
    1164  * @param   pszUserName             User name on guest to use for the copy operation.
    1165  * @param   pszPassword             Password of user account.
    1166  * @param   fFlags                  Copy flags.
    1167  */
    1168 static int ctrlCopyFileToGuest(IGuest *pGuest, const char *pszSource, const char *pszDest,
    1169                                const char *pszUserName, const char *pszPassword,
    1170                                uint32_t fFlags)
    1171 {
    1172     AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
    1173     AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
    1174     AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    1175     AssertPtrReturn(pszUserName, VERR_INVALID_POINTER);
    1176     AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
    1177 
    1178     int vrc = VINF_SUCCESS;
    1179     ComPtr<IProgress> progress;
    1180     HRESULT rc = pGuest->CopyToGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(),
    1181                                      Bstr(pszUserName).raw(), Bstr(pszPassword).raw(),
    1182                                      fFlags, progress.asOutParam());
    1183     if (FAILED(rc))
    1184         vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    1185     else
    1186     {
    1187         rc = showProgress(progress);
    1188         if (FAILED(rc))
    1189             vrc = ctrlPrintProgressError(progress);
    1190     }
    1191     return vrc;
    1192 }
    1193 
    1194 /**
    1195  * Copys a file from guest to the host.
    1196  *
    1197  * @return  IPRT status code.
    1198  * @param   pGuest                  IGuest interface pointer.
    1199  * @param   pszSource               Source path of existing guest file to copy to the host.
    1200  * @param   pszDest                 Destination path/file on host to copy the file to.
    1201  * @param   pszUserName             User name on guest to use for the copy operation.
    1202  * @param   pszPassword             Password of user account.
    1203  * @param   fFlags                  Copy flags.
    1204  */
    1205 static int ctrlCopyFileToHost(IGuest *pGuest, const char *pszSource, const char *pszDest,
    1206                               const char *pszUserName, const char *pszPassword,
    1207                               uint32_t fFlags)
    1208 {
    1209     AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
    1210     AssertPtrReturn(pszSource, VERR_INVALID_POINTER);
    1211     AssertPtrReturn(pszDest, VERR_INVALID_POINTER);
    1212     AssertPtrReturn(pszUserName, VERR_INVALID_POINTER);
    1213     AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
    1214 
    1215     int vrc = VINF_SUCCESS;
    1216     ComPtr<IProgress> progress;
    1217     HRESULT rc = pGuest->CopyFromGuest(Bstr(pszSource).raw(), Bstr(pszDest).raw(),
    1218                                        Bstr(pszUserName).raw(), Bstr(pszPassword).raw(),
    1219                                        fFlags, progress.asOutParam());
    1220     if (FAILED(rc))
    1221         vrc = ctrlPrintError(pGuest, COM_IIDOF(IGuest));
    1222     else
    1223     {
    1224         rc = showProgress(progress);
    1225         if (FAILED(rc))
    1226             vrc = ctrlPrintProgressError(progress);
    1227     }
    1228     return vrc;
    1229 }
    1230 
    1231 static int ctrlCopyToDestDirectory(IGuest *pGuest, bool fVerbose, bool fDryRun, bool fHostToGuest,
    1232                                    const char *pszSourceDir,
    1233                                    const char *pszDestRoot, const char *pszDestSub, const char *pszFileName,
    1234                                    uint32_t uFlags, const char *pszUsername, const char *pszPassword)
    1235 {
    1236     AssertPtrReturn(pGuest, VERR_INVALID_POINTER);
    1237     AssertPtrReturn(pszDestRoot, VERR_INVALID_POINTER);
    1238     AssertPtrReturn(pszDestSub, VERR_INVALID_POINTER);
    1239     AssertPtrReturn(pszFileName, VERR_INVALID_POINTER);
    1240     AssertPtrReturn(pszSourceDir, VERR_INVALID_POINTER);
    1241     AssertPtrReturn(pszUsername, VERR_INVALID_POINTER);
    1242     AssertPtrReturn(pszPassword, VERR_INVALID_POINTER);
    1243 
    1244     int iLen;
    1245     char *pszSource;
    1246     if (!strlen(pszDestSub))
    1247         iLen = RTStrAPrintf(&pszSource, "%s/%s", pszSourceDir, pszFileName);
    1248     else
    1249         iLen = RTStrAPrintf(&pszSource, "%s/%s/%s",
    1250                             pszSourceDir, pszDestSub, pszFileName);
    1251     if (!iLen)
    1252         return VERR_NO_MEMORY;
    1253 
    1254     char *pszDest;
    1255     if (!strlen(pszDestSub))
    1256         iLen = RTStrAPrintf(&pszDest, "%s/%s", pszDestRoot, pszFileName);
    1257     else
    1258         iLen = RTStrAPrintf(&pszDest, "%s/%s/%s", pszDestRoot, pszDestSub,
    1259                             pszFileName);
    1260     if (!iLen)
    1261     {
    1262         RTStrFree(pszSource);
    1263         return VERR_NO_MEMORY;
    1264     }
    1265 
    1266     if (fVerbose)
    1267         RTPrintf("\"%s\" -> \"%s\"\n", pszSource, pszDest);
    1268 
    1269     int rc = VINF_SUCCESS;
    1270 
    1271     /* Finally copy the desired file (if no dry run selected). */
    1272     if (!fDryRun)
    1273     {
    1274         if (fHostToGuest)
    1275             rc = ctrlCopyFileToGuest(pGuest, pszSource, pszDest,
    1276                                      pszUsername, pszPassword, uFlags);
    1277         else
    1278             rc = ctrlCopyFileToHost(pGuest, pszSource, pszDest,
    1279                                     pszUsername, pszPassword, uFlags);
    1280     }
    1281     RTStrFree(pszSource);
    1282     RTStrFree(pszDest);
    1283 
    1284     return rc;
     1347        /* If there's anything (like a file name or a filter),
     1348         * strip it! */
     1349        RTPathStripFilename(pszNewRoot);
     1350        *ppszSourceRoot = pszNewRoot;
     1351    }
     1352
     1353    return VINF_SUCCESS;
     1354}
     1355
     1356static void ctrlCopyFreeSourceRoot(char *pszSourceRoot)
     1357{
     1358    RTStrFree(pszSourceRoot);
    12851359}
    12861360
     
    14151489    }
    14161490
    1417     /* Strip traling slash from destination path. */
    1418     RTPathStripTrailingSlash(Utf8Dest.mutableRaw());
    1419     Utf8Dest.jolt();
    1420 
    1421     /*
    1422      * Here starts the actual fun!
    1423      */
    1424     for (unsigned long s = 0; s < vecSources.size(); s++)
    1425     {
    1426         char *pszSourceDir;
    1427         if (RTDirExists(vecSources[s].mSource.c_str()))
    1428             pszSourceDir = RTStrDup(vecSources[s].mSource.c_str());
    1429         else
    1430         {
    1431             pszSourceDir = RTStrDup(vecSources[s].mSource.c_str());
    1432             RTPathStripFilename(pszSourceDir);
    1433         }
    1434 
    1435         uint32_t cObjects = 0;
    1436         DESTDIRMAP mapDest;
    1437         const char *pszDestRoot = Utf8Dest.c_str();
    1438 
    1439         if (fHostToGuest)
    1440             vrc = ctrlCopyConstructDestinationsForGuest(vecSources[s], fFlags, pszDestRoot,
    1441                                                         mapDest, &cObjects);
    1442         else
    1443             vrc = ctrlCopyConstructDestinationsForHost(guest, Utf8UserName.c_str(), Utf8Password.c_str(),
    1444                                                        vecSources[s], fFlags, pszDestRoot,
    1445                                                        mapDest, &cObjects);
    1446         if (RT_FAILURE(vrc))
    1447         {
    1448             if (   fVerbose
    1449                 && vrc == VERR_FILE_NOT_FOUND)
    1450             {
    1451                 RTPrintf("Warning: Source \"%s\" does not exist, skipping!\n",
    1452                          vecSources[s].mSource.c_str());
    1453             }
    1454         }
    1455         else
    1456         {
    1457             /*
    1458              * Prepare directory structure of each destination directory.
    1459              */
    1460             DESTDIRMAPITER itDest;
    1461             for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++)
    1462             {
    1463                 if (fVerbose)
     1491    /* Create the copy context -- it contains all information
     1492     * the routines need to know when handling the actual copying. */
     1493    PCOPYCONTEXT pContext;
     1494    vrc = ctrlCopyContextCreate(guest, fVerbose, fHostToGuest,
     1495                                Utf8UserName.c_str(), Utf8Password.c_str(),
     1496                                &pContext);
     1497    if (RT_FAILURE(vrc))
     1498    {
     1499        RTMsgError("Unable to create copy context, rc=%Rrc\n", vrc);
     1500        return RTEXITCODE_FAILURE;
     1501    }
     1502
     1503    /* If the destination is a path, (try to) create it. */
     1504    const char *pszDest = Utf8Dest.c_str();
     1505    AssertPtr(pszDest);
     1506    size_t lenDest = strlen(pszDest);
     1507    if (   lenDest
     1508         ||pszDest[lenDest - 1] == '/'
     1509        || pszDest[lenDest - 1] == '\\')
     1510    {
     1511        vrc = ctrlCopyDirCreate(pContext, pszDest);
     1512    }
     1513
     1514    if (RT_SUCCESS(vrc))
     1515    {
     1516        /*
     1517         * Here starts the actual fun!
     1518         * Handle all given sources one by one.
     1519         */
     1520        for (unsigned long s = 0; s < vecSources.size(); s++)
     1521        {
     1522            const char *pszSource = vecSources[s].mSource.c_str();
     1523            const char *pszFilter = vecSources[s].mFilter.c_str();
     1524
     1525            char *pszSourceRoot;
     1526            vrc = ctrlCopyCreateSourceRoot(pszSource, &pszSourceRoot);
     1527            if (RT_FAILURE(vrc))
     1528            {
     1529                RTMsgError("Unable to create source root, rc=%Rrc\n", vrc);
     1530                break;
     1531            }
     1532
     1533            if (fVerbose)
     1534                RTPrintf("Source: %s\n", pszSource);
     1535
     1536            /* @todo Files with filter?? */
     1537            bool fExists;
     1538            vrc = ctrlCopyFileExistsOnSource(pContext, pszSource, &fExists);
     1539            if (RT_SUCCESS(vrc))
     1540            {
     1541                if (fExists)
    14641542                {
    1465                     const char *pszSubDir = itDest->first.c_str();
    1466                     AssertPtr(pszSubDir);
    1467                     if (!strlen(pszSubDir))
    1468                         RTPrintf("Preparing directory \"%s\" ...\n", pszDestRoot);
     1543                    /* Single file. */
     1544                    char *pszDest;
     1545                    vrc = ctrlCopyTranslatePath(pContext, pszSourceRoot, pszSource,
     1546                                                Utf8Dest.c_str(), &pszDest);
     1547                    if (RT_SUCCESS(vrc))
     1548                    {
     1549                        vrc = ctrlCopyFileToTarget(pContext, pszSource,
     1550                                                   pszDest, fFlags);
     1551                        RTStrFree(pszDest);
     1552                    }
    14691553                    else
    1470                         RTPrintf("Preparing directory \"%s/%s\" ...\n", pszDestRoot,
    1471                                  itDest->first.c_str());
     1554                    {
     1555                        RTMsgError("Unable to translate path for \"%s\", rc=%Rrc\n",
     1556                                   pszSource, vrc);
     1557                    }
    14721558                }
    1473                 if (!fDryRun)
    1474                     vrc = ctrlCopyPrepareDestDirectory(guest, fHostToGuest,
    1475                                                        pszDestRoot, itDest->first.c_str(),
    1476                                                        Utf8UserName.c_str(), Utf8Password.c_str());
    1477                 if (RT_FAILURE(vrc))
    1478                     break;
     1559                else
     1560                {
     1561                    if (   (RT_SUCCESS(ctrlCopyDirExistsOnSource(pContext, pszSource, &fExists))
     1562                            && fExists)
     1563                        || (   RT_SUCCESS(ctrlCopyDirExistsOnSource(pContext, pszSourceRoot, &fExists))
     1564                            && fExists
     1565                            && pszFilter)
     1566                       )
     1567                    {
     1568                        /* Directory (with filter?). */
     1569                        vrc = ctrlCopyDirToTarget(pContext, pszSource, pszFilter,
     1570                                                  Utf8Dest.c_str(), fFlags, NULL /* Subdir */);
     1571                    }
     1572                }
     1573            }
     1574
     1575            ctrlCopyFreeSourceRoot(pszSourceRoot);
     1576
     1577            if (   RT_SUCCESS(vrc)
     1578                && !fExists)
     1579            {
     1580                RTMsgError("Warning: Source \"%s\" does not exist, skipping!\n",
     1581                           pszSource);
     1582                continue;
    14791583            }
    14801584
    14811585            if (RT_FAILURE(vrc))
    1482                 break;
    1483 
    1484             if (fVerbose)
    1485             {
    1486                 if (!cObjects)
    1487                     RTPrintf("Warning: Source \"%s\" has no (matching) files to copy, skipping!\n",
    1488                              vecSources[s].mSource.c_str());
    1489                 else
    1490                     RTPrintf("Copying \"%s\" (%u files) ...\n",
    1491                              vecSources[s].mSource.c_str(), cObjects);
    1492             }
    1493 
    1494             /*
    1495              * Copy files of each destination root directory to the guest.
    1496              */
    1497             for (itDest = mapDest.begin(); itDest != mapDest.end(); itDest++)
    1498             {
    1499                 if (fVerbose && itDest->second.size())
    1500                 {
    1501                     if (itDest->first.isEmpty())
    1502                         RTPrintf("Copying %u files ...\n", itDest->second.size());
    1503                     else
    1504                         RTPrintf("Copying directory \"%s\" (%u files) ...\n",
    1505                                  itDest->first.c_str(), itDest->second.size());
    1506                 }
    1507 
    1508                 for (unsigned long l = 0; l < itDest->second.size(); l++)
    1509                 {
    1510                     vrc = ctrlCopyToDestDirectory(guest, fVerbose, fDryRun, fHostToGuest,
    1511                                                   pszSourceDir,
    1512                                                   pszDestRoot, itDest->first.c_str() /* Sub directory */,
    1513                                                   itDest->second[l].mFileName.c_str() /* Filename */,
    1514                                                   fFlags, Utf8UserName.c_str(), Utf8Password.c_str());
    1515                     if (RT_FAILURE(vrc))
    1516                         break;
    1517                 }
    1518 
    1519                 if (RT_FAILURE(vrc))
    1520                     break;
    1521             }
    1522 
    1523             if (RT_FAILURE(vrc))
    1524                 break;
    1525         }
    1526 
    1527         RTStrFree(pszSourceDir);
    1528     }
     1586            {
     1587                RTMsgError("Error processing \"%s\", rc=%Rrc\n",
     1588                           pszSource, vrc);
     1589                break;
     1590            }
     1591        }
     1592    }
     1593
     1594    ctrlCopyContextFree(pContext);
    15291595
    15301596    return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
     
    16321698                ctrlPrintError(guest, COM_IIDOF(IGuest)); /* Return code ignored, save original rc. */
    16331699                break;
     1700            }
     1701
     1702            it++;
     1703        }
     1704
     1705        if (FAILED(hrc))
     1706            rcExit = RTEXITCODE_FAILURE;
     1707    }
     1708
     1709    return rcExit;
     1710}
     1711
     1712static int handleCtrlStat(ComPtr<IGuest> guest, HandlerArg *pArg)
     1713{
     1714    AssertPtrReturn(pArg, VERR_INVALID_PARAMETER);
     1715
     1716    /*
     1717     * Parse arguments.
     1718     *
     1719     * Note! No direct returns here, everyone must go thru the cleanup at the
     1720     *       end of this function.
     1721     */
     1722    static const RTGETOPTDEF s_aOptions[] =
     1723    {
     1724        /** @todo Implement "--dereference/-L", and "--file-system/-f" later! */
     1725        { "--password",            'p',         RTGETOPT_REQ_STRING  },
     1726        { "--username",            'u',         RTGETOPT_REQ_STRING  },
     1727        { "--verbose",             'v',         RTGETOPT_REQ_NOTHING }
     1728    };
     1729
     1730    int ch;
     1731    RTGETOPTUNION ValueUnion;
     1732    RTGETOPTSTATE GetState;
     1733    RTGetOptInit(&GetState, pArg->argc, pArg->argv,
     1734                 s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_OPTS_FIRST);
     1735
     1736    Utf8Str Utf8UserName;
     1737    Utf8Str Utf8Password;
     1738
     1739    bool fVerbose = false;
     1740    DESTDIRMAP mapDirs;
     1741
     1742    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
     1743    while (   (ch = RTGetOpt(&GetState, &ValueUnion))
     1744           && rcExit == RTEXITCODE_SUCCESS)
     1745    {
     1746        /* For options that require an argument, ValueUnion has received the value. */
     1747        switch (ch)
     1748        {
     1749            case 'p': /* Password */
     1750                Utf8Password = ValueUnion.psz;
     1751                break;
     1752
     1753            case 'u': /* User name */
     1754                Utf8UserName = ValueUnion.psz;
     1755                break;
     1756
     1757            case 'v': /* Verbose */
     1758                fVerbose = true;
     1759                break;
     1760
     1761            case VINF_GETOPT_NOT_OPTION:
     1762            {
     1763                mapDirs[ValueUnion.psz]; /* Add element to check to map. */
     1764                break;
     1765            }
     1766
     1767            default:
     1768                rcExit = RTGetOptPrintError(ch, &ValueUnion);
     1769                break;
     1770        }
     1771    }
     1772
     1773    uint32_t cDirs = mapDirs.size();
     1774    if (rcExit == RTEXITCODE_SUCCESS && !cDirs)
     1775        rcExit = errorSyntax(USAGE_GUESTCONTROL, "No element to check specified!");
     1776
     1777    if (rcExit == RTEXITCODE_SUCCESS && Utf8UserName.isEmpty())
     1778        rcExit = errorSyntax(USAGE_GUESTCONTROL, "No user name specified!");
     1779
     1780    if (rcExit == RTEXITCODE_SUCCESS)
     1781    {
     1782        /*
     1783         * Create the directories.
     1784         */
     1785        HRESULT hrc = S_OK;
     1786
     1787        DESTDIRMAPITER it = mapDirs.begin();
     1788        while (it != mapDirs.end())
     1789        {
     1790            if (fVerbose)
     1791                RTPrintf("Checking for element \"%s\" ...\n", it->first.c_str());
     1792
     1793            BOOL fExists;
     1794            hrc = guest->FileExists(Bstr(it->first).raw(),
     1795                                    Bstr(Utf8UserName).raw(), Bstr(Utf8Password).raw(),
     1796                                    &fExists);
     1797            if (FAILED(hrc))
     1798            {
     1799                ctrlPrintError(guest, COM_IIDOF(IGuest)); /* Return code ignored, save original rc. */
     1800                break;
     1801            }
     1802            else
     1803            {
     1804                /** @todo: Output vbox_stat's stdout output to get more information about
     1805                 *         what happened. */
     1806
     1807                /* If there's at least one element which does not exist on the guest,
     1808                 * drop out with exitcode 1. */
     1809                if (!fExists)
     1810                {
     1811                    RTPrintf("Cannot stat for element \"%s\": No such file or directory.\n",
     1812                             it->first.c_str());
     1813                    rcExit = RTEXITCODE_FAILURE;
     1814                }
    16341815            }
    16351816
     
    17721953            rcExit = handleCtrlExecProgram(guest, &arg);
    17731954        }
    1774 #if 0
    17751955        else if (!strcmp(pArg->argv[1], "copyfrom"))
    17761956        {
     
    17781958                                      false /* Guest to host */);
    17791959        }
    1780 #endif
    17811960        else if (   !strcmp(pArg->argv[1], "copyto")
    17821961                 || !strcmp(pArg->argv[1], "cp"))
     
    17921971            rcExit = handleCtrlCreateDirectory(guest, &arg);
    17931972        }
     1973        else if (   !strcmp(pArg->argv[1], "stat"))
     1974        {
     1975            rcExit = handleCtrlStat(guest, &arg);
     1976        }
    17941977        else if (   !strcmp(pArg->argv[1], "updateadditions")
    17951978                 || !strcmp(pArg->argv[1], "updateadds"))
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