VirtualBox

Changeset 71251 in vbox for trunk


Ignore:
Timestamp:
Mar 7, 2018 11:20:00 AM (7 years ago)
Author:
vboxsync
Message:

Guest Control/[Directory|File]CopyFrom: Factored out the fileCopyFrom session task routines to also implement copying entire directories from the guest within Main. Work in progress.

Location:
trunk/src/VBox
Files:
4 edited

Legend:

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

    r71231 r71251  
    219219        }
    220220
    221         const char* GetSource() const
    222         {
    223             return mSource.c_str();
    224         }
    225 
    226         const char* GetFilter() const
    227         {
    228             return mFilter.c_str();
     221        Utf8Str GetSource() const
     222        {
     223            return mSource;
     224        }
     225
     226        Utf8Str GetFilter() const
     227        {
     228            return mFilter;
    229229        }
    230230
     
    17671767    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
    17681768
    1769     Utf8Str strSource;
    17701769    const char *pszDst = NULL;
    17711770    bool fDryRun = false;
     
    18531852    for (unsigned long s = 0; s < vecSources.size(); s++)
    18541853    {
    1855         char *pszSrc = RTStrDup(vecSources[s].GetSource());
    1856         AssertPtrBreakStmt(pszSrc, vrc = VERR_NO_MEMORY);
    1857         const char *pszFilter = vecSources[s].GetFilter();
    1858         RT_NOREF(pszFilter);
    1859         /* pszFilter can be NULL if not set. */
     1854        Utf8Str strSrc    = vecSources[s].GetSource();
     1855        Utf8Str strFilter = vecSources[s].GetFilter();
     1856        RT_NOREF(strFilter);
     1857        /* strFilter can be NULL if not set. */
    18601858
    18611859        if (fHostToGuest)
    18621860        {
    1863             if (RTFileExists(pszSrc))
     1861            if (RTFileExists(strSrc.c_str()))
    18641862            {
    18651863                SafeArray<FileCopyFlag_T> copyFlags;
    1866                 rc = pCtx->pGuestSession->FileCopyToGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(),
     1864                rc = pCtx->pGuestSession->FileCopyToGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(),
    18671865                                                          ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
    18681866            }
    1869             else if (RTDirExists(pszSrc))
     1867            else if (RTDirExists(strSrc.c_str()))
    18701868            {
    18711869                SafeArray<DirectoryCopyFlag_T> copyFlags;
    18721870                copyFlags.push_back(DirectoryCopyFlag_CopyIntoExisting);
    1873                 rc = pCtx->pGuestSession->DirectoryCopyToGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(),
     1871                rc = pCtx->pGuestSession->DirectoryCopyToGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(),
    18741872                                                               ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
    18751873            }
    18761874            else if (pCtx->cVerbose)
    1877                 RTPrintf("Warning: \"%s\" does not exist or is not a file/directory, skipping ...\n", pszSrc);
     1875                RTPrintf("Warning: \"%s\" does not exist or is not a file/directory, skipping ...\n", strSrc.c_str());
    18781876        }
    18791877        else
    18801878        {
    1881             SafeArray<FileCopyFlag_T> copyFlags;
    1882             rc = pCtx->pGuestSession->FileCopyFromGuest(Bstr(pszSrc).raw(), Bstr(pszDst).raw(),
    1883                                                         ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
     1879            if (   strSrc.endsWith("/")
     1880                || strSrc.endsWith("\\"))
     1881            {
     1882                SafeArray<DirectoryCopyFlag_T> copyFlags;
     1883                copyFlags.push_back(DirectoryCopyFlag_CopyIntoExisting);
     1884                rc = pCtx->pGuestSession->DirectoryCopyFromGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(),
     1885                                                                 ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
     1886            }
     1887            else
     1888            {
     1889                SafeArray<FileCopyFlag_T> copyFlags;
     1890                rc = pCtx->pGuestSession->FileCopyFromGuest(Bstr(strSrc).raw(), Bstr(pszDst).raw(),
     1891                                                            ComSafeArrayAsInParam(copyFlags), pProgress.asOutParam());
     1892            }
    18841893        }
    18851894    }
  • trunk/src/VBox/Main/include/GuestSessionImpl.h

    r71231 r71251  
    8282    /** @name File handling primitives.
    8383     * @{ */
    84     int fileCopyToGuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile,
    85                           uint64_t cbOffset, uint64_t cbSize); /**< r=bird: 'cbOffset' makes no sense what so ever. It should be 'off', or do you mean sizeof(uint64_t)? */
    86     int fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
     84    int fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
     85                       PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize);
     86    int fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
     87    int fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile,
     88                     uint64_t cbOffset, uint64_t cbSize); /**< r=bird: 'cbOffset' makes no sense what so ever. It should be 'off', or do you mean sizeof(uint64_t)? */
     89    int fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
    8790    /** @}  */
    8891
     
    195198
    196199    SessionTaskCopyFileTo(GuestSession *pSession,
    197                           const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);
     200                          const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
    198201    SessionTaskCopyFileTo(GuestSession *pSession,
    199202                          PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
    200                           const Utf8Str &strDest, uint32_t uFlags);
     203                          const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
    201204    virtual ~SessionTaskCopyFileTo(void);
    202205    int Run(void);
     
    204207protected:
    205208
    206     Utf8Str  mSource;
    207     PRTFILE  mSourceFile;
    208     size_t   mSourceOffset;
    209     uint64_t mSourceSize;
    210     Utf8Str  mDest;
    211     uint32_t mCopyFileFlags;
     209    Utf8Str        mSource;
     210    PRTFILE        mSourceFile;
     211    size_t         mSourceOffset;
     212    uint64_t       mSourceSize;
     213    Utf8Str        mDest;
     214    FileCopyFlag_T mFileCopyFlags;
    212215};
    213216
     
    220223
    221224    SessionTaskCopyFileFrom(GuestSession *pSession,
    222                         const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags);
     225                        const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
    223226    virtual ~SessionTaskCopyFileFrom(void);
    224227    int Run(void);
     
    226229protected:
    227230
    228     Utf8Str  mSource;
    229     Utf8Str  mDest;
    230     uint32_t mFlags;
     231    Utf8Str        mSource;
     232    Utf8Str        mDest;
     233    FileCopyFlag_T mFileCopyFlags;
    231234};
    232235
  • trunk/src/VBox/Main/src-client/GuestSessionImpl.cpp

    r71232 r71251  
    26002600                                             const std::vector<DirectoryCopyFlag_T> &aFlags, ComPtr<IProgress> &aProgress)
    26012601{
    2602     RT_NOREF(aSource, aDestination, aFlags, aProgress);
    2603     ReturnComNotImplemented();
     2602    LogFlowThisFuncEnter();
     2603
     2604    if (RT_UNLIKELY((aSource.c_str()) == NULL || *(aSource.c_str()) == '\0'))
     2605        return setError(E_INVALIDARG, tr("No source directory specified"));
     2606
     2607    if (RT_UNLIKELY((aDestination.c_str()) == NULL || *(aDestination.c_str()) == '\0'))
     2608        return setError(E_INVALIDARG, tr("No destination directory specified"));
     2609
     2610    uint32_t fFlags = DirectoryCopyFlag_None;
     2611    if (aFlags.size())
     2612    {
     2613        for (size_t i = 0; i < aFlags.size(); i++)
     2614            fFlags |= aFlags[i];
     2615    }
     2616    /** @todo Validate flags. */
     2617
     2618    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
     2619
     2620    HRESULT hr = S_OK;
     2621
     2622    try
     2623    {
     2624        SessionTaskCopyDirFrom *pTask = NULL;
     2625        ComObjPtr<Progress> pProgress;
     2626        try
     2627        {
     2628            pTask = new SessionTaskCopyDirFrom(this /* GuestSession */, aSource, aDestination, "" /* strFilter */,
     2629                                               (DirectoryCopyFlag_T)fFlags);
     2630        }
     2631        catch(...)
     2632        {
     2633            hr = setError(VBOX_E_IPRT_ERROR, tr("Failed to create SessionTaskCopyDirFrom object"));
     2634            throw;
     2635        }
     2636
     2637        hr = pTask->Init(Utf8StrFmt(tr("Copying directory \"%s\" from guest to \"%s\" on the host"),
     2638                                    aSource.c_str(), aDestination.c_str()));
     2639        if (FAILED(hr))
     2640        {
     2641            delete pTask;
     2642            hr = setError(VBOX_E_IPRT_ERROR,
     2643                          tr("Creating progress object for SessionTaskCopyDirFrom object failed"));
     2644            throw hr;
     2645        }
     2646
     2647        hr = pTask->createThreadWithType(RTTHREADTYPE_MAIN_HEAVY_WORKER);
     2648
     2649        if (SUCCEEDED(hr))
     2650        {
     2651            /* Return progress to the caller. */
     2652            pProgress = pTask->GetProgressObject();
     2653            hr = pProgress.queryInterfaceTo(aProgress.asOutParam());
     2654        }
     2655        else
     2656            hr = setError(VBOX_E_IPRT_ERROR,
     2657                          tr("Starting thread for copying directory \"%s\" from guest to \"%s\" on the host failed"),
     2658                          aSource.c_str(), aDestination.c_str());
     2659    }
     2660    catch(std::bad_alloc &)
     2661    {
     2662        hr = E_OUTOFMEMORY;
     2663    }
     2664    catch(HRESULT eHR)
     2665    {
     2666        hr = eHR;
     2667        LogFlowThisFunc(("Exception was caught in the function\n"));
     2668    }
     2669
     2670    return hr;
    26042671}
    26052672
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r71242 r71251  
    261261
    262262/**
     263 * Copies a file from the guest to the host, extended version.
     264 *
     265 * @return VBox status code.
     266 * @param  strSource            Full path of source file on the guest to copy.
     267 * @param  strDest              Full destination path and file name (host style) to copy file to.
     268 * @param  enmFileCopyFlags     File copy flags. Currently not used.
     269 * @param  pFile                Destination file handle to use for accessing the host file.
     270 *                              The caller is responsible of opening / closing the file accordingly.
     271 * @param  cbOffset             Offset (in bytes) where to start copying the source file.
     272 *                              Currently unused, must be 0.
     273 * @param  cbSize               Size (in bytes) to copy from the source file.
     274 *                              Currently unused, must be 0.
     275 */
     276int GuestSessionTask::fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
     277                                     PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize)
     278{
     279    RT_NOREF(enmFileCopyFlags, cbOffset, cbSize);
     280
     281    AssertReturn(cbOffset == 0, VERR_NOT_IMPLEMENTED);
     282    AssertReturn(cbSize   == 0, VERR_NOT_IMPLEMENTED);
     283
     284    RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */
     285
     286    /*
     287     * Note: There will be races between querying file size + reading the guest file's
     288     *       content because we currently *do not* lock down the guest file when doing the
     289     *       actual operations.
     290     ** @todo Use the IGuestFile API for locking down the file on the guest!
     291     */
     292    GuestFsObjData objData;
     293    int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
     294    int rc = mSession->i_fileQueryInfoInternal(strSource, false /*fFollowSymlinks*/, objData, &rcGuest);
     295    if (RT_FAILURE(rc))
     296    {
     297        switch (rc)
     298        {
     299            case VERR_GSTCTL_GUEST_ERROR:
     300                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
     301                break;
     302
     303            default:
     304                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     305                                    Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"),
     306                                               strSource.c_str(), rc));
     307                break;
     308        }
     309    }
     310    else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */
     311    {
     312        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     313                            Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), strSource.c_str()));
     314        rc = VERR_NOT_A_FILE;
     315    }
     316
     317    if (RT_FAILURE(rc))
     318        return rc;
     319
     320    GuestProcessStartupInfo procInfo;
     321    procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
     322                                strSource.c_str(), strDest.c_str(), objData.mObjectSize);
     323    procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
     324    procInfo.mFlags      = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
     325
     326    /* Set arguments.*/
     327    procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
     328    procInfo.mArguments.push_back(strSource);            /* Which file to output? */
     329
     330    /* Startup process. */
     331    ComObjPtr<GuestProcess> pProcess;
     332    rc = mSession->i_processCreateExInternal(procInfo, pProcess);
     333    if (RT_SUCCESS(rc))
     334        rc = pProcess->i_startProcess(msTimeout, &rcGuest);
     335
     336    if (RT_FAILURE(rc))
     337    {
     338        switch (rc)
     339        {
     340            case VERR_GSTCTL_GUEST_ERROR:
     341                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
     342                break;
     343
     344            default:
     345                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     346                                    Utf8StrFmt(GuestSession::tr(
     347                                   "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
     348                                   strSource.c_str(), rc));
     349                break;
     350        }
     351
     352        return rc;
     353    }
     354
     355    ProcessWaitResult_T waitRes;
     356    BYTE byBuf[_64K];
     357
     358    BOOL fCanceled = FALSE;
     359    uint64_t cbWrittenTotal = 0;
     360    uint64_t cbToRead = objData.mObjectSize;
     361
     362    for (;;)
     363    {
     364        rc = pProcess->i_waitFor(ProcessWaitForFlag_StdOut, msTimeout, waitRes, &rcGuest);
     365        if (RT_FAILURE(rc))
     366        {
     367            switch (rc)
     368            {
     369                case VERR_GSTCTL_GUEST_ERROR:
     370                    setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
     371                    break;
     372
     373                default:
     374                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     375                                        Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
     376                                                   strSource.c_str(), rc));
     377                    break;
     378            }
     379
     380            break;
     381        }
     382
     383        if (   waitRes == ProcessWaitResult_StdOut
     384            || waitRes == ProcessWaitResult_WaitFlagNotSupported)
     385        {
     386            /* If the guest does not support waiting for stdin, we now yield in
     387             * order to reduce the CPU load due to busy waiting. */
     388            if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
     389                RTThreadYield(); /* Optional, don't check rc. */
     390
     391            uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
     392            rc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
     393                                      msTimeout, byBuf, sizeof(byBuf),
     394                                      &cbRead, &rcGuest);
     395            if (RT_FAILURE(rc))
     396            {
     397                switch (rc)
     398                {
     399                    case VERR_GSTCTL_GUEST_ERROR:
     400                        setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
     401                        break;
     402
     403                    default:
     404                        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     405                                            Utf8StrFmt(GuestSession::tr("Reading from guest file \"%s\" (offset %RU64) failed: %Rrc"),
     406                                                       strSource.c_str(), cbWrittenTotal, rc));
     407                        break;
     408                }
     409
     410                break;
     411            }
     412
     413            if (cbRead)
     414            {
     415                rc = RTFileWrite(*pFile, byBuf, cbRead, NULL /* No partial writes */);
     416                if (RT_FAILURE(rc))
     417                {
     418                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     419                                        Utf8StrFmt(GuestSession::tr("Writing to host file \"%s\" (%RU64 bytes left) failed: %Rrc"),
     420                                                   strDest.c_str(), cbToRead, rc));
     421                    break;
     422                }
     423
     424                /* Only subtract bytes reported written by the guest. */
     425                Assert(cbToRead >= cbRead);
     426                cbToRead -= cbRead;
     427
     428                /* Update total bytes written to the guest. */
     429                cbWrittenTotal += cbRead;
     430                Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize);
     431
     432                /* Did the user cancel the operation above? */
     433                if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
     434                    && fCanceled)
     435                    break;
     436
     437                rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0)));
     438                if (RT_FAILURE(rc))
     439                    break;
     440            }
     441        }
     442        else
     443           break;
     444
     445    } /* for */
     446
     447    LogFlowThisFunc(("rc=%Rrc, rcGuest=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
     448                     rc, rcGuest, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead));
     449
     450    /*
     451     * Wait on termination of guest process until it completed all operations.
     452     */
     453    if (   !fCanceled
     454        || RT_SUCCESS(rc))
     455    {
     456        rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest);
     457        if (   RT_FAILURE(rc)
     458            || waitRes != ProcessWaitResult_Terminate)
     459        {
     460            if (RT_FAILURE(rc))
     461                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     462                                    Utf8StrFmt(
     463                                    GuestSession::tr("Waiting on termination for copying file \"%s\" from guest failed: %Rrc"),
     464                                    strSource.c_str(), rc));
     465            else
     466            {
     467                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     468                                    Utf8StrFmt(GuestSession::tr(
     469                                               "Waiting on termination for copying file \"%s\" from guest failed with wait result %ld"),
     470                                               strSource.c_str(), waitRes));
     471                rc = VERR_GENERAL_FAILURE; /* Fudge. */
     472            }
     473        }
     474    }
     475
     476    if (RT_FAILURE(rc))
     477        return rc;
     478
     479    /** @todo this code sequence is duplicated in CopyTo   */
     480    ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally;
     481    HRESULT hrc = pProcess->COMGETTER(Status(&procStatus));
     482    if (!SUCCEEDED(hrc))
     483        procStatus = ProcessStatus_TerminatedAbnormally;
     484
     485    LONG exitCode = 42424242;
     486    hrc = pProcess->COMGETTER(ExitCode(&exitCode));
     487    if (!SUCCEEDED(hrc))
     488        exitCode = 42424242;
     489
     490    if (   procStatus != ProcessStatus_TerminatedNormally
     491        || exitCode != 0)
     492    {
     493        LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode));
     494        if (procStatus == ProcessStatus_TerminatedNormally)
     495            rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode);
     496        else
     497            rc = VERR_GENERAL_FAILURE;
     498        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     499                            Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to host failed: %Rrc"),
     500                                       strSource.c_str(), rc));
     501    }
     502    /*
     503     * Even if we succeeded until here make sure to check whether we really transfered
     504     * everything.
     505     */
     506    else if (   objData.mObjectSize > 0
     507             && cbWrittenTotal == 0)
     508    {
     509        /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
     510         * to the destination -> access denied. */
     511        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     512                            Utf8StrFmt(GuestSession::tr("Writing guest file \"%s\" to host to \"%s\" failed: Access denied"),
     513                                       strSource.c_str(), strDest.c_str()));
     514        rc = VERR_ACCESS_DENIED;
     515    }
     516    else if (cbWrittenTotal < (uint64_t)objData.mObjectSize)
     517    {
     518        /* If we did not copy all let the user know. */
     519        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     520                            Utf8StrFmt(GuestSession::tr("Copying guest file \"%s\" to host to \"%s\" failed (%RU64/%RI64 bytes transfered)"),
     521                                       strSource.c_str(), strDest.c_str(), cbWrittenTotal, objData.mObjectSize));
     522        rc = VERR_INTERRUPTED;
     523    }
     524
     525    return rc;
     526}
     527
     528/**
     529 * Copies a file from the guest to the host.
     530 *
     531 * @return VBox status code.
     532 * @param  strSource            Full path of source file on the guest to copy.
     533 * @param  strDest              Full destination path and file name (host style) to copy file to.
     534 * @param  enmFileCopyFlags     File copy flags.
     535 */
     536int GuestSessionTask::fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
     537{
     538    RTFILE hFile;
     539    int rc = RTFileOpen(&hFile, strDest.c_str(),
     540                        RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
     541    if (RT_FAILURE(rc))
     542    {
     543        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     544                            Utf8StrFmt(GuestSession::tr("Opening/creating destination file on host \"%s\" failed: %Rrc"),
     545                                       strDest.c_str(), rc));
     546        return rc;
     547    }
     548
     549    rc = fileCopyFromEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset, unused */, 0 /* Size, unused */);
     550
     551    int rc2 = RTFileClose(hFile);
     552    AssertRC(rc2);
     553
     554    return rc;
     555}
     556
     557/**
    263558 * Copies a file from the host to the guest, extended version.
    264559 *
     
    272567 * @param  cbSize               Size (in bytes) to copy from the source file.
    273568 */
    274 int GuestSessionTask::fileCopyToGuestEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
    275                                         PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize)
     569int GuestSessionTask::fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
     570                                   PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize)
    276571{
    277572    /** @todo Implement sparse file support? */
     
    537832 * @param  enmFileCopyFlags     File copy flags.
    538833 */
    539 int GuestSessionTask::fileCopyToGuest(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
     834int GuestSessionTask::fileCopyTo(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
    540835{
    541836    int rc;
     
    571866            }
    572867            else
    573                 rc = fileCopyToGuestEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize);
     868                rc = fileCopyToEx(strSource, strDest, enmFileCopyFlags, &hFile, 0 /* Offset */, cbSize);
    574869
    575870             RTFileClose(hFile);
     
    629924}
    630925
     926SessionTaskCopyDirFrom::SessionTaskCopyDirFrom(GuestSession *pSession, const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
     927                                               DirectoryCopyFlag_T enmDirCopyFlags)
     928                                               : GuestSessionTask(pSession)
     929                                               , mSource(strSource)
     930                                               , mDest(strDest)
     931                                               , mFilter(strFilter)
     932                                               , mDirCopyFlags(enmDirCopyFlags)
     933{
     934    m_strTaskName = "gctlCpyDirFrm";
     935}
     936
     937SessionTaskCopyDirFrom::~SessionTaskCopyDirFrom(void)
     938{
     939
     940}
     941
     942/**
     943 * Copys a directory (tree) from guest to the host.
     944 *
     945 * @return  IPRT status code.
     946 * @param   strSource               Source directory on the guest to copy to the host.
     947 * @param   strFilter               DOS-style wildcard filter (?, *).  Optional.
     948 * @param   strDest                 Destination directory on the host.
     949 * @param   fRecursive,             Whether to recursively copy the directory contents or not.
     950 * @param   fFollowSymlinks         Whether to follow symlinks or not.
     951 * @param   strSubDir               Current sub directory to handle. Needs to NULL and only
     952 *                                  is needed for recursion.
     953 */
     954int SessionTaskCopyDirFrom::directoryCopyToHost(const Utf8Str &strSource, const Utf8Str &strFilter,
     955                                                const Utf8Str &strDest, bool fRecursive, bool fFollowSymlinks,
     956                                                const Utf8Str &strSubDir /* For recursion. */)
     957{
     958    Utf8Str strSrcDir    = strSource;
     959    Utf8Str strDstDir    = strDest;
     960    Utf8Str strSrcSubDir = strSubDir;
     961
     962    /* Validation and sanity. */
     963    if (   !strSrcDir.endsWith("/")
     964        && !strSrcDir.endsWith("\\"))
     965        strSrcDir += "/";
     966
     967    if (   !strDstDir.endsWith("/")
     968        && !strDstDir.endsWith("\\"))
     969        strDstDir+= "/";
     970
     971    if (    strSrcSubDir.isNotEmpty() /* Optional, for recursion. */
     972        && !strSrcSubDir.endsWith("/")
     973        && !strSrcSubDir.endsWith("\\"))
     974        strSrcSubDir += "/";
     975
     976    Utf8Str strSrcCur = strSrcDir + strSrcSubDir;
     977
     978    LogFlowFunc(("Entering '%s'\n", strSrcCur.c_str()));
     979
     980    int rc;
     981
     982    if (strSrcSubDir.isNotEmpty())
     983    {
     984        const uint32_t fMode = 0700; /** @todo */
     985
     986        rc = RTDirCreate(Utf8Str(strDstDir + strSrcSubDir).c_str(), fMode, 0);
     987        if (RT_FAILURE(rc))
     988            return rc;
     989    }
     990
     991    GuestDirectoryOpenInfo dirOpenInfo;
     992    dirOpenInfo.mFilter = strFilter;
     993    dirOpenInfo.mPath   = strSrcCur;
     994    dirOpenInfo.mFlags  = 0; /** @todo Handle flags? */
     995
     996    ComObjPtr <GuestDirectory> pDir; int rcGuest;
     997    rc = mSession->i_directoryOpenInternal(dirOpenInfo, pDir, &rcGuest);
     998    if (RT_FAILURE(rc))
     999    {
     1000        switch (rc)
     1001        {
     1002            case VERR_INVALID_PARAMETER:
     1003               setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1004                                    Utf8StrFmt(GuestSession::tr("Opening directory \"%s\" failed: Invalid parameter"), dirOpenInfo.mPath.c_str()));
     1005               break;
     1006
     1007            case VERR_GSTCTL_GUEST_ERROR:
     1008                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
     1009                break;
     1010
     1011            default:
     1012                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1013                                    Utf8StrFmt(GuestSession::tr("Opening directory \"%s\" failed: %Rrc"), dirOpenInfo.mPath.c_str(), rc));
     1014                break;
     1015        }
     1016
     1017        return rc;
     1018    }
     1019
     1020RT_NOREF(fRecursive, fFollowSymlinks);
     1021
     1022    ComObjPtr<GuestFsObjInfo> fsObjInfo;
     1023    while (RT_SUCCESS(rc = pDir->i_readInternal(fsObjInfo, &rcGuest)))
     1024    {
     1025        com::Bstr aName;
     1026        fsObjInfo->COMGETTER(Name)(aName.asOutParam());
     1027        LogFlowThisFunc(("strName=%ls\n", aName.raw()));
     1028    }
     1029
     1030    if (rc == VERR_NO_MORE_FILES) /* Reading done? */
     1031        rc = VINF_SUCCESS;
     1032
     1033    pDir->i_closeInternal(&rcGuest);
     1034
     1035    LogFlowFunc(("Leaving '%s', rc=%Rrc\n", strSrcCur.c_str(), rc));
     1036    return rc;
     1037}
     1038
     1039int SessionTaskCopyDirFrom::Run(void)
     1040{
     1041    LogFlowThisFuncEnter();
     1042
     1043    AutoCaller autoCaller(mSession);
     1044    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     1045
     1046    const bool fRecursive      = true; /** @todo Make this configurable. */
     1047    const bool fFollowSymlinks = true; /** @todo Make this configurable. */
     1048    const uint32_t fDirMode    = 0700; /* Play safe by default. */
     1049
     1050    int rc = VINF_SUCCESS;
     1051
     1052    /* Create the root target directory on the host.
     1053     * The target directory might already exist on the host (based on mDirCopyFlags). */
     1054    const bool fExists = RTDirExists(mDest.c_str());
     1055    if (   fExists
     1056        && !(mDirCopyFlags & DirectoryCopyFlag_CopyIntoExisting))
     1057    {
     1058        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1059                            Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" exists when it must not"), mDest.c_str()));
     1060        rc = VERR_ALREADY_EXISTS;
     1061    }
     1062    else if (!fExists)
     1063    {
     1064        rc = RTDirCreate(mDest.c_str(), fDirMode, 0);
     1065        if (RT_FAILURE(rc))
     1066            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1067                                Utf8StrFmt(GuestSession::tr("Error creating destination directory \"%s\", rc=%Rrc"),
     1068                                           mDest.c_str(), rc));
     1069    }
     1070
     1071    if (RT_FAILURE(rc))
     1072        return rc;
     1073
     1074    RTDIR hDir;
     1075    rc = RTDirOpen(&hDir, mDest.c_str());
     1076    if (RT_FAILURE(rc))
     1077    {
     1078        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     1079                            Utf8StrFmt(GuestSession::tr("Error opening destination directory \"%s\", rc=%Rrc"),
     1080                                       mDest.c_str(), rc));
     1081        return rc;
     1082    }
     1083
     1084    /* At this point the directory on the host was created and (hopefully) is ready
     1085     * to receive further content. */
     1086    rc = directoryCopyToHost(mSource, mFilter, mDest, fRecursive, fFollowSymlinks,
     1087                             "" /* strSubDir; for recursion */);
     1088    if (RT_SUCCESS(rc))
     1089        rc = setProgressSuccess();
     1090
     1091    RTDirClose(hDir);
     1092
     1093    LogFlowFuncLeaveRC(rc);
     1094    return rc;
     1095}
     1096
    6311097SessionTaskCopyDirTo::SessionTaskCopyDirTo(GuestSession *pSession,
    6321098                                           const Utf8Str &strSource, const Utf8Str &strDest, const Utf8Str &strFilter,
     
    6381104                                           , mDirCopyFlags(enmDirCopyFlags)
    6391105{
    640     m_strTaskName = "gctlCopyDirTo";
     1106    m_strTaskName = "gctlCpyDirTo";
    6411107}
    6421108
     
    7611227                        Utf8Str strSrcFile = strSrcDir + strSrcSubDir + Utf8Str(pDirEntry->szName);
    7621228                        Utf8Str strDstFile = strDstDir + strSrcSubDir + Utf8Str(pDirEntry->szName);
    763                         rc = fileCopyToGuest(strSrcFile, strDstFile, FileCopyFlag_None);
     1229                        rc = fileCopyTo(strSrcFile, strDstFile, FileCopyFlag_None);
    7641230                    }
    7651231                    break;
     
    8171283
    8181284SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession,
    819                                              const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
    820                                              : GuestSessionTask(pSession),
    821                                                mSource(strSource),
    822                                                mSourceFile(NULL),
    823                                                mSourceOffset(0),
    824                                                mSourceSize(0),
    825                                                mDest(strDest)
    826 {
    827     mCopyFileFlags = uFlags;
    828     m_strTaskName = "gctlCopyFileTo";
     1285                                             const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
     1286                                             : GuestSessionTask(pSession)
     1287                                             , mSource(strSource)
     1288                                             , mSourceFile(NULL)
     1289                                             , mSourceOffset(0)
     1290                                             , mSourceSize(0)
     1291                                             , mDest(strDest)
     1292                                             , mFileCopyFlags(enmFileCopyFlags)
     1293{
     1294    m_strTaskName = "gctlCpyFileTo";
    8291295}
    8301296
    8311297SessionTaskCopyFileTo::SessionTaskCopyFileTo(GuestSession *pSession,
    8321298                                             PRTFILE pSourceFile, size_t cbSourceOffset, uint64_t cbSourceSize,
    833                                              const Utf8Str &strDest, uint32_t uFlags)
     1299                                             const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
    8341300                                             : GuestSessionTask(pSession)
    835 {
    836     mSourceFile    = pSourceFile;
    837     mSourceOffset  = cbSourceOffset;
    838     mSourceSize    = cbSourceSize;
    839     mDest          = strDest;
    840     mCopyFileFlags = uFlags;
    841     m_strTaskName = "gctlCopyFileToWithHandle";
     1301                                             , mSourceFile(pSourceFile)
     1302                                             , mSourceOffset(cbSourceOffset)
     1303                                             , mSourceSize(cbSourceSize)
     1304                                             , mDest(strDest)
     1305                                             , mFileCopyFlags(enmFileCopyFlags)
     1306{
     1307    m_strTaskName = "gctlCpyFileToH";
    8421308}
    8431309
     
    8751341    }
    8761342
    877     if (mCopyFileFlags)
     1343    if (mFileCopyFlags)
    8781344    {
    8791345        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    8801346                            Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"),
    881                             mCopyFileFlags));
     1347                            mFileCopyFlags));
    8821348        return VERR_NOT_IMPLEMENTED;
    8831349    }
     
    9311397    {
    9321398        if (mSourceFile) /* Use existing file handle. */
    933             rc = fileCopyToGuestEx(mSource, mDest, (FileCopyFlag_T)mCopyFileFlags, mSourceFile, mSourceOffset, mSourceSize);
     1399            rc = fileCopyToEx(mSource, mDest, (FileCopyFlag_T)mFileCopyFlags, mSourceFile, mSourceOffset, mSourceSize);
    9341400        else
    935             rc = fileCopyToGuest(mSource, mDest, (FileCopyFlag_T)mCopyFileFlags);
     1401            rc = fileCopyTo(mSource, mDest, (FileCopyFlag_T)mFileCopyFlags);
    9361402
    9371403        if (RT_SUCCESS(rc))
     
    9441410
    9451411SessionTaskCopyFileFrom::SessionTaskCopyFileFrom(GuestSession *pSession,
    946                                                  const Utf8Str &strSource, const Utf8Str &strDest, uint32_t uFlags)
     1412                                                 const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags)
    9471413                                                 : GuestSessionTask(pSession)
    948 {
    949     mSource = strSource;
    950     mDest   = strDest;
    951     mFlags  = uFlags;
    952     m_strTaskName = "gctlCopyFileFrom";
     1414                                                 , mSource(strSource)
     1415                                                 , mDest(strDest)
     1416                                                 , mFileCopyFlags(enmFileCopyFlags)
     1417{
     1418    m_strTaskName = "gctlCpyFileFrm";
    9531419}
    9541420
     
    9651431    if (FAILED(autoCaller.rc())) return autoCaller.rc();
    9661432
    967     RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */
    968 
    969     /*
    970      * Note: There will be races between querying file size + reading the guest file's
    971      *       content because we currently *do not* lock down the guest file when doing the
    972      *       actual operations.
    973      ** @todo Use the IGuestFile API for locking down the file on the guest!
    974      */
    975     GuestFsObjData objData;
    976     int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
    977     int rc = mSession->i_fileQueryInfoInternal(Utf8Str(mSource), false /*fFollowSymlinks*/, objData, &rcGuest);
    978     if (RT_FAILURE(rc))
    979     {
    980         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    981                             Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"),
    982                                        mSource.c_str(), rc));
    983     }
    984     else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */
    985     {
    986         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    987                             Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), mSource.c_str()));
    988         rc = VERR_NOT_A_FILE;
    989     }
    990 
     1433    int rc = fileCopyFrom(mSource, mDest, mFileCopyFlags);
    9911434    if (RT_SUCCESS(rc))
    992     {
    993         RTFILE fileDest;
    994         rc = RTFileOpen(&fileDest, mDest.c_str(),
    995                         RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
    996         if (RT_FAILURE(rc))
    997         {
    998             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    999                                 Utf8StrFmt(GuestSession::tr("Opening/creating destination file on host \"%s\" failed: %Rrc"),
    1000                                            mDest.c_str(), rc));
    1001         }
    1002         else
    1003         {
    1004             GuestProcessStartupInfo procInfo;
    1005             procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
    1006                                         mSource.c_str(), mDest.c_str(), objData.mObjectSize);
    1007             procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
    1008             procInfo.mFlags      = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
    1009 
    1010             /* Set arguments.*/
    1011             procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
    1012             procInfo.mArguments.push_back(mSource);              /* Which file to output? */
    1013 
    1014             /* Startup process. */
    1015             ComObjPtr<GuestProcess> pProcess;
    1016             rc = mSession->i_processCreateExInternal(procInfo, pProcess);
    1017             if (RT_SUCCESS(rc))
    1018                 rc = pProcess->i_startProcess(msTimeout, &rcGuest);
    1019             if (RT_FAILURE(rc))
    1020             {
    1021                 switch (rc)
    1022                 {
    1023                     case VERR_GSTCTL_GUEST_ERROR:
    1024                         setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    1025                         break;
    1026 
    1027                     default:
    1028                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1029                                             Utf8StrFmt(GuestSession::tr(
    1030                                            "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
    1031                                            mSource.c_str(), rc));
    1032                         break;
    1033                 }
    1034             }
    1035             else
    1036             {
    1037                 ProcessWaitResult_T waitRes;
    1038                 BYTE byBuf[_64K];
    1039 
    1040                 BOOL fCanceled = FALSE;
    1041                 uint64_t cbWrittenTotal = 0;
    1042                 uint64_t cbToRead = objData.mObjectSize;
    1043 
    1044                 for (;;)
    1045                 {
    1046                     rc = pProcess->i_waitFor(ProcessWaitForFlag_StdOut, msTimeout, waitRes, &rcGuest);
    1047                     if (RT_FAILURE(rc))
    1048                     {
    1049                         switch (rc)
    1050                         {
    1051                             case VERR_GSTCTL_GUEST_ERROR:
    1052                                 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    1053                                 break;
    1054 
    1055                             default:
    1056                                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1057                                                     Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
    1058                                                                mSource.c_str(), rc));
    1059                                 break;
    1060                         }
    1061 
    1062                         break;
    1063                     }
    1064 
    1065                     if (   waitRes == ProcessWaitResult_StdOut
    1066                         || waitRes == ProcessWaitResult_WaitFlagNotSupported)
    1067                     {
    1068                         /* If the guest does not support waiting for stdin, we now yield in
    1069                          * order to reduce the CPU load due to busy waiting. */
    1070                         if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
    1071                             RTThreadYield(); /* Optional, don't check rc. */
    1072 
    1073                         uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    1074                         rc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    1075                                                   msTimeout, byBuf, sizeof(byBuf),
    1076                                                   &cbRead, &rcGuest);
    1077                         if (RT_FAILURE(rc))
    1078                         {
    1079                             switch (rc)
    1080                             {
    1081                                 case VERR_GSTCTL_GUEST_ERROR:
    1082                                     setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    1083                                     break;
    1084 
    1085                                 default:
    1086                                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1087                                                         Utf8StrFmt(GuestSession::tr("Reading from guest file \"%s\" (offset %RU64) failed: %Rrc"),
    1088                                                                    mSource.c_str(), cbWrittenTotal, rc));
    1089                                     break;
    1090                             }
    1091 
    1092                             break;
    1093                         }
    1094 
    1095                         if (cbRead)
    1096                         {
    1097                             rc = RTFileWrite(fileDest, byBuf, cbRead, NULL /* No partial writes */);
    1098                             if (RT_FAILURE(rc))
    1099                             {
    1100                                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1101                                                     Utf8StrFmt(GuestSession::tr("Writing to host file \"%s\" (%RU64 bytes left) failed: %Rrc"),
    1102                                                                 mDest.c_str(), cbToRead, rc));
    1103                                 break;
    1104                             }
    1105 
    1106                             /* Only subtract bytes reported written by the guest. */
    1107                             Assert(cbToRead >= cbRead);
    1108                             cbToRead -= cbRead;
    1109 
    1110                             /* Update total bytes written to the guest. */
    1111                             cbWrittenTotal += cbRead;
    1112                             Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize);
    1113 
    1114                             /* Did the user cancel the operation above? */
    1115                             if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    1116                                 && fCanceled)
    1117                                 break;
    1118 
    1119                             rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0)));
    1120                             if (RT_FAILURE(rc))
    1121                                 break;
    1122                         }
    1123                     }
    1124                     else
    1125                     {
    1126                         break;
    1127                     }
    1128 
    1129                 } /* for */
    1130 
    1131                 LogFlowThisFunc(("rc=%Rrc, rcGuest=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
    1132                                  rc, rcGuest, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead));
    1133 
    1134                 /*
    1135                  * Wait on termination of guest process until it completed all operations.
    1136                  */
    1137                 if (   !fCanceled
    1138                     || RT_SUCCESS(rc))
    1139                 {
    1140                     rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest);
    1141                     if (   RT_FAILURE(rc)
    1142                         || waitRes != ProcessWaitResult_Terminate)
    1143                     {
    1144                         if (RT_FAILURE(rc))
    1145                             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1146                                                 Utf8StrFmt(
    1147                                                 GuestSession::tr("Waiting on termination for copying file \"%s\" from guest failed: %Rrc"),
    1148                                                 mSource.c_str(), rc));
    1149                         else
    1150                         {
    1151                             setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1152                                                 Utf8StrFmt(GuestSession::tr(
    1153                                                            "Waiting on termination for copying file \"%s\" from guest failed with wait result %ld"),
    1154                                                            mSource.c_str(), waitRes));
    1155                             rc = VERR_GENERAL_FAILURE; /* Fudge. */
    1156                         }
    1157                     }
    1158                 }
    1159 
    1160                 if (RT_SUCCESS(rc))
    1161                 {
    1162                     /** @todo this code sequence is duplicated in CopyTo   */
    1163                     ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally;
    1164                     HRESULT hrc = pProcess->COMGETTER(Status(&procStatus));
    1165                     if (!SUCCEEDED(hrc))
    1166                         procStatus = ProcessStatus_TerminatedAbnormally;
    1167 
    1168                     LONG exitCode = 42424242;
    1169                     hrc = pProcess->COMGETTER(ExitCode(&exitCode));
    1170                     if (!SUCCEEDED(hrc))
    1171                         exitCode = 42424242;
    1172 
    1173                     if (   procStatus != ProcessStatus_TerminatedNormally
    1174                         || exitCode != 0)
    1175                     {
    1176                         LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode));
    1177                         if (procStatus == ProcessStatus_TerminatedNormally)
    1178                             rc = GuestProcessTool::i_exitCodeToRc(procInfo, exitCode);
    1179                         else
    1180                             rc = VERR_GENERAL_FAILURE;
    1181                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1182                                             Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to host failed: %Rrc"),
    1183                                                        mSource.c_str(), rc));
    1184                     }
    1185                     /*
    1186                      * Even if we succeeded until here make sure to check whether we really transfered
    1187                      * everything.
    1188                      */
    1189                     else if (   objData.mObjectSize > 0
    1190                              && cbWrittenTotal == 0)
    1191                     {
    1192                         /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    1193                          * to the destination -> access denied. */
    1194                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1195                                             Utf8StrFmt(GuestSession::tr("Writing guest file \"%s\" to host to \"%s\" failed: Access denied"),
    1196                                                        mSource.c_str(), mDest.c_str()));
    1197                         rc = VERR_ACCESS_DENIED;
    1198                     }
    1199                     else if (cbWrittenTotal < (uint64_t)objData.mObjectSize)
    1200                     {
    1201                         /* If we did not copy all let the user know. */
    1202                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    1203                                             Utf8StrFmt(GuestSession::tr("Copying guest file \"%s\" to host to \"%s\" failed (%RU64/%RI64 bytes transfered)"),
    1204                                                        mSource.c_str(), mDest.c_str(), cbWrittenTotal, objData.mObjectSize));
    1205                         rc = VERR_INTERRUPTED;
    1206                     }
    1207                     else
    1208                         rc = setProgressSuccess();
    1209                 }
    1210             }
    1211 
    1212             RTFileClose(fileDest);
    1213         }
    1214     }
     1435        rc = setProgressSuccess();
    12151436
    12161437    LogFlowFuncLeaveRC(rc);
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