VirtualBox

Changeset 71796 in vbox


Ignore:
Timestamp:
Apr 9, 2018 7:26:50 PM (6 years ago)
Author:
vboxsync
Message:

Guest Control/Main: GuestSessionTask::fileCopyFrom[Ex] are now using IGuestFile objects for also having proper locking and seeking support instead of just cat'ing data to the host. Also implemented the CopyFileFlags while I was at it.

Location:
trunk/src/VBox/Main
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/include/GuestSessionImplTasks.h

    r71657 r71796  
    7979    /** @name File handling primitives.
    8080     * @{ */
    81     int fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
    82                        PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize);
     81    int fileCopyFromEx(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T enmFileCopyFlags,
     82                       uint64_t cbOffset, uint64_t cbSize);
    8383    int fileCopyFrom(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags);
    8484    int fileCopyToEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags, PRTFILE pFile,
  • trunk/src/VBox/Main/src-client/GuestSessionImplTasks.cpp

    r71667 r71796  
    266266 *
    267267 * @return VBox status code.
    268  * @param  strSource            Full path of source file on the guest to copy.
    269  * @param  strDest              Full destination path and file name (host style) to copy file to.
    270  * @param  enmFileCopyFlags     File copy flags. Currently not used.
    271  * @param  pFile                Destination file handle to use for accessing the host file.
    272  *                              The caller is responsible of opening / closing the file accordingly.
    273  * @param  cbOffset             Offset (in bytes) where to start copying the source file.
    274  *                              Currently unused, must be 0.
    275  * @param  cbSize               Size (in bytes) to copy from the source file.
    276  *                              Currently unused, must be 0.
     268 * @param  srcFile            Guest file (source) to copy to the host. Must be in opened and ready state already.
     269 * @param  phDstFile          Pointer to host file handle (destination) to copy to. Must be in opened and ready state already.
     270 * @param  enmFileCopyFlags   File copy flags.
     271 * @param  uOffset            Offset (in bytes) where to start copying the source file.
     272 * @param  cbSize             Size (in bytes) to copy from the source file.
    277273 */
    278 int GuestSessionTask::fileCopyFromEx(const Utf8Str &strSource, const Utf8Str &strDest, FileCopyFlag_T enmFileCopyFlags,
    279                                      PRTFILE pFile, uint64_t cbOffset, uint64_t cbSize)
    280 {
    281     RT_NOREF(enmFileCopyFlags, cbOffset, cbSize);
    282 
    283     AssertReturn(cbOffset == 0, VERR_NOT_IMPLEMENTED);
    284     AssertReturn(cbSize   == 0, VERR_NOT_IMPLEMENTED);
    285 
    286     RTMSINTERVAL msTimeout = 30 * 1000; /** @todo 30s timeout for all actions. Make this configurable? */
    287 
    288     LogFlowFunc(("strSource=%s, strDest=%s, fCopyFlags=0x%x, cbOff=%RU64, cbSize=%RU64\n",
    289                  strSource.c_str(), strDest.c_str(), enmFileCopyFlags, cbOffset, cbSize));
    290 
    291     /*
    292      * Note: There will be races between querying file size + reading the guest file's
    293      *       content because we currently *do not* lock down the guest file when doing the
    294      *       actual operations.
    295      ** @todo Use the IGuestFile API for locking down the file on the guest!
    296      */
    297     GuestFsObjData objData;
    298     int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
    299     int rc = mSession->i_fileQueryInfo(strSource, false /*fFollowSymlinks*/, objData, &rcGuest);
    300     if (RT_FAILURE(rc))
    301     {
    302         switch (rc)
    303         {
    304             case VERR_GSTCTL_GUEST_ERROR:
    305                 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    306                 break;
    307 
    308             default:
    309                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    310                                     Utf8StrFmt(GuestSession::tr("Querying guest file information for \"%s\" failed: %Rrc"),
    311                                                strSource.c_str(), rc));
    312                 break;
    313         }
    314     }
    315     else if (objData.mType != FsObjType_File) /* Only single files are supported at the moment. */
    316     {
    317         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    318                             Utf8StrFmt(GuestSession::tr("Object \"%s\" on the guest is not a file"), strSource.c_str()));
    319         rc = VERR_NOT_A_FILE;
     274int GuestSessionTask::fileCopyFromEx(ComObjPtr<GuestFile> &srcFile, PRTFILE phDstFile, FileCopyFlag_T enmFileCopyFlags,
     275                                     uint64_t uOffset, uint64_t cbSize)
     276{
     277    RT_NOREF(enmFileCopyFlags);
     278
     279    BOOL fCanceled = FALSE;
     280    uint64_t cbWrittenTotal = 0;
     281    uint64_t cbToRead       = cbSize;
     282
     283    uint32_t uTimeoutMs = 30 * 1000; /* 30s timeout. */
     284
     285    int rc = VINF_SUCCESS;
     286
     287    if (uOffset)
     288    {
     289        uint64_t puOffset;
     290        rc = srcFile->i_seekAt(uOffset, GUEST_FILE_SEEKTYPE_BEGIN, uTimeoutMs, &puOffset);
     291        if (RT_FAILURE(rc))
     292        {
     293            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     294                                Utf8StrFmt(GuestSession::tr("Seeking to offset %RU64) failed: %Rrc"), uOffset, rc));
     295            return rc;
     296        }
     297    }
     298
     299    BYTE byBuf[_64K];
     300    while (cbToRead)
     301    {
     302        uint32_t cbRead;
     303        const uint32_t cbChunk = RT_MIN(cbToRead, sizeof(byBuf));
     304        rc = srcFile->i_readData(cbChunk, uTimeoutMs, byBuf, sizeof(byBuf), &cbRead);
     305        if (RT_FAILURE(rc))
     306        {
     307            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     308                                Utf8StrFmt(GuestSession::tr("Reading %RU32 bytes @ %RU64, failed: %Rrc"), cbChunk, cbWrittenTotal, rc));
     309            break;
     310        }
     311
     312        rc = RTFileWrite(*phDstFile, byBuf, cbRead, NULL /* No partial writes */);
     313        if (RT_FAILURE(rc))
     314        {
     315            setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     316                                Utf8StrFmt(GuestSession::tr("Writing to %RU32 bytes to file failed: %Rrc"), cbRead, rc));
     317            break;
     318        }
     319
     320        Assert(cbToRead >= cbRead);
     321        cbToRead -= cbRead;
     322
     323        /* Update total bytes written to the guest. */
     324        cbWrittenTotal += cbRead;
     325        Assert(cbWrittenTotal <= cbSize);
     326
     327        /* Did the user cancel the operation above? */
     328        if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
     329            && fCanceled)
     330            break;
     331
     332        rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)cbSize / 100.0)));
     333        if (RT_FAILURE(rc))
     334            break;
    320335    }
    321336
     
    323338        return rc;
    324339
    325     GuestProcessStartupInfo procInfo;
    326     procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" from guest to the host to \"%s\" (%RI64 bytes)"),
    327                                 strSource.c_str(), strDest.c_str(), objData.mObjectSize);
    328     procInfo.mExecutable = Utf8Str(VBOXSERVICE_TOOL_CAT);
    329     procInfo.mFlags      = ProcessCreateFlag_Hidden | ProcessCreateFlag_WaitForStdOut;
    330 
    331     /* Set arguments.*/
    332     procInfo.mArguments.push_back(procInfo.mExecutable); /* Set argv0. */
    333     procInfo.mArguments.push_back(strSource);            /* Which file to output? */
    334 
    335     /* Startup process. */
    336     ComObjPtr<GuestProcess> pProcess;
    337     rc = mSession->i_processCreateEx(procInfo, pProcess);
    338     if (RT_SUCCESS(rc))
    339         rc = pProcess->i_startProcess(msTimeout, &rcGuest);
    340 
    341     if (RT_FAILURE(rc))
    342     {
    343         switch (rc)
    344         {
    345             case VERR_GSTCTL_GUEST_ERROR:
    346                 setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    347                 break;
    348 
    349             default:
    350                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    351                                     Utf8StrFmt(GuestSession::tr(
    352                                    "Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
    353                                    strSource.c_str(), rc));
    354                 break;
    355         }
    356 
    357         return rc;
    358     }
    359 
    360     ProcessWaitResult_T waitRes;
    361     BYTE byBuf[_64K];
    362 
    363     BOOL fCanceled = FALSE;
    364     uint64_t cbWrittenTotal = 0;
    365     uint64_t cbToRead = objData.mObjectSize;
    366 
    367     for (;;)
    368     {
    369         rc = pProcess->i_waitFor(ProcessWaitForFlag_StdOut, msTimeout, waitRes, &rcGuest);
    370         if (RT_FAILURE(rc))
    371         {
    372             switch (rc)
    373             {
    374                 case VERR_GSTCTL_GUEST_ERROR:
    375                     setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    376                     break;
    377 
    378                 default:
    379                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    380                                         Utf8StrFmt(GuestSession::tr("Error while creating guest process for copying file \"%s\" from guest to host: %Rrc"),
    381                                                    strSource.c_str(), rc));
    382                     break;
    383             }
    384 
    385             break;
    386         }
    387 
    388         if (   waitRes == ProcessWaitResult_StdOut
    389             || waitRes == ProcessWaitResult_WaitFlagNotSupported)
    390         {
    391             /* If the guest does not support waiting for stdin, we now yield in
    392              * order to reduce the CPU load due to busy waiting. */
    393             if (waitRes == ProcessWaitResult_WaitFlagNotSupported)
    394                 RTThreadYield(); /* Optional, don't check rc. */
    395 
    396             uint32_t cbRead = 0; /* readData can return with VWRN_GSTCTL_OBJECTSTATE_CHANGED. */
    397             rc = pProcess->i_readData(OUTPUT_HANDLE_ID_STDOUT, sizeof(byBuf),
    398                                       msTimeout, byBuf, sizeof(byBuf),
    399                                       &cbRead, &rcGuest);
    400             if (RT_FAILURE(rc))
    401             {
    402                 switch (rc)
    403                 {
    404                     case VERR_GSTCTL_GUEST_ERROR:
    405                         setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestProcess::i_guestErrorToString(rcGuest));
    406                         break;
    407 
    408                     default:
    409                         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    410                                             Utf8StrFmt(GuestSession::tr("Reading from guest file \"%s\" (offset %RU64) failed: %Rrc"),
    411                                                        strSource.c_str(), cbWrittenTotal, rc));
    412                         break;
    413                 }
    414 
    415                 break;
    416             }
    417 
    418             if (cbRead)
    419             {
    420                 rc = RTFileWrite(*pFile, byBuf, cbRead, NULL /* No partial writes */);
    421                 if (RT_FAILURE(rc))
    422                 {
    423                     setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    424                                         Utf8StrFmt(GuestSession::tr("Writing to host file \"%s\" (%RU64 bytes left) failed: %Rrc"),
    425                                                    strDest.c_str(), cbToRead, rc));
    426                     break;
    427                 }
    428 
    429                 /* Only subtract bytes reported written by the guest. */
    430                 Assert(cbToRead >= cbRead);
    431                 cbToRead -= cbRead;
    432 
    433                 /* Update total bytes written to the guest. */
    434                 cbWrittenTotal += cbRead;
    435                 Assert(cbWrittenTotal <= (uint64_t)objData.mObjectSize);
    436 
    437                 /* Did the user cancel the operation above? */
    438                 if (   SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled)))
    439                     && fCanceled)
    440                     break;
    441 
    442                 rc = setProgress((ULONG)(cbWrittenTotal / ((uint64_t)objData.mObjectSize / 100.0)));
    443                 if (RT_FAILURE(rc))
    444                     break;
    445             }
    446         }
    447         else
    448            break;
    449 
    450     } /* for */
    451 
    452     LogFlowThisFunc(("rc=%Rrc, rcGuest=%Rrc, waitRes=%ld, cbWrittenTotal=%RU64, cbSize=%RI64, cbToRead=%RU64\n",
    453                      rc, rcGuest, waitRes, cbWrittenTotal, objData.mObjectSize, cbToRead));
    454 
    455     /*
    456      * Wait on termination of guest process until it completed all operations.
    457      */
    458     if (   !fCanceled
    459         || RT_SUCCESS(rc))
    460     {
    461         rc = pProcess->i_waitFor(ProcessWaitForFlag_Terminate, msTimeout, waitRes, &rcGuest);
    462         if (   RT_FAILURE(rc)
    463             || waitRes != ProcessWaitResult_Terminate)
    464         {
    465             if (RT_FAILURE(rc))
    466                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    467                                     Utf8StrFmt(
    468                                     GuestSession::tr("Waiting on termination for copying file \"%s\" from guest failed: %Rrc"),
    469                                     strSource.c_str(), rc));
    470             else
    471             {
    472                 setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    473                                     Utf8StrFmt(GuestSession::tr(
    474                                                "Waiting on termination for copying file \"%s\" from guest failed with wait result %ld"),
    475                                                strSource.c_str(), waitRes));
    476                 rc = VERR_GENERAL_FAILURE; /* Fudge. */
    477             }
    478         }
    479     }
    480 
    481     if (RT_FAILURE(rc))
    482         return rc;
    483 
    484     /** @todo this code sequence is duplicated in CopyTo   */
    485     ProcessStatus_T procStatus = ProcessStatus_TerminatedAbnormally;
    486     HRESULT hrc = pProcess->COMGETTER(Status(&procStatus));
    487     if (!SUCCEEDED(hrc))
    488         procStatus = ProcessStatus_TerminatedAbnormally;
    489 
    490     LONG exitCode = 42424242;
    491     hrc = pProcess->COMGETTER(ExitCode(&exitCode));
    492     if (!SUCCEEDED(hrc))
    493         exitCode = 42424242;
    494 
    495     if (   procStatus != ProcessStatus_TerminatedNormally
    496         || exitCode != 0)
    497     {
    498         LogFlowThisFunc(("procStatus=%d, exitCode=%d\n", procStatus, exitCode));
    499         if (procStatus == ProcessStatus_TerminatedNormally)
    500             rc = GuestProcessTool::exitCodeToRc(procInfo, exitCode);
    501         else
    502             rc = VERR_GENERAL_FAILURE;
    503         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    504                             Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to host failed: %Rrc"),
    505                                        strSource.c_str(), rc));
    506     }
    507340    /*
    508341     * Even if we succeeded until here make sure to check whether we really transfered
    509342     * everything.
    510343     */
    511     else if (   objData.mObjectSize > 0
    512              && cbWrittenTotal == 0)
     344    if (   cbSize > 0
     345        && cbWrittenTotal == 0)
    513346    {
    514347        /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write
    515348         * to the destination -> access denied. */
    516349        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    517                             Utf8StrFmt(GuestSession::tr("Writing guest file \"%s\" to host to \"%s\" failed: Access denied"),
    518                                        strSource.c_str(), strDest.c_str()));
     350                            Utf8StrFmt(GuestSession::tr("Writing guest file to host failed: Access denied")));
    519351        rc = VERR_ACCESS_DENIED;
    520352    }
    521     else if (cbWrittenTotal < (uint64_t)objData.mObjectSize)
     353    else if (cbWrittenTotal < cbSize)
    522354    {
    523355        /* If we did not copy all let the user know. */
    524356        setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    525                             Utf8StrFmt(GuestSession::tr("Copying guest file \"%s\" to host to \"%s\" failed (%RU64/%RI64 bytes transfered)"),
    526                                        strSource.c_str(), strDest.c_str(), cbWrittenTotal, objData.mObjectSize));
     357                            Utf8StrFmt(GuestSession::tr("Copying guest file to host to failed (%RU64/%RU64 bytes transfered)"),
     358                                       cbWrittenTotal, cbSize));
    527359        rc = VERR_INTERRUPTED;
    528360    }
     
    535367 * Copies a file from the guest to the host.
    536368 *
    537  * @return VBox status code.
     369 * @return VBox status code. VINF_NO_CHANGE if file was skipped.
    538370 * @param  strSource            Full path of source file on the guest to copy.
    539371 * @param  strDest              Full destination path and file name (host style) to copy file to.
     
    544376    LogFlowThisFunc(("strSource=%s, strDest=%s, enmFileCopyFlags=0x%x\n", strSource.c_str(), strDest.c_str(), enmFileCopyFlags));
    545377
     378    GuestFileOpenInfo srcOpenInfo;
     379    RT_ZERO(srcOpenInfo);
     380    srcOpenInfo.mFileName     = strSource;
     381    srcOpenInfo.mOpenAction   = FileOpenAction_OpenExisting;
     382    srcOpenInfo.mAccessMode   = FileAccessMode_ReadOnly;
     383    srcOpenInfo.mSharingMode  = FileSharingMode_All; /** @todo Use _Read when implemented. */
     384
     385    ComObjPtr<GuestFile> srcFile;
     386
     387    GuestFsObjData srcObjData;
     388    RT_ZERO(srcObjData);
     389
     390    int rcGuest = VERR_IPE_UNINITIALIZED_STATUS;
     391    int rc = mSession->i_fsQueryInfo(strSource.c_str(), TRUE /* fFollowSymlinks */, srcObjData, &rcGuest);
     392    if (RT_FAILURE(rc))
     393    {
     394        switch (rc)
     395        {
     396            case VERR_GSTCTL_GUEST_ERROR:
     397                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest));
     398                break;
     399
     400            default:
     401                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     402                                    Utf8StrFmt(GuestSession::tr("Source file lookup for \"%s\" failed: %Rrc"),
     403                                               strSource.c_str(), rc));
     404                break;
     405        }
     406    }
     407    else
     408    {
     409        switch (srcObjData.mType)
     410        {
     411            case FsObjType_File:
     412                break;
     413
     414            case FsObjType_Symlink:
     415                if (!(enmFileCopyFlags & FileCopyFlag_FollowLinks))
     416                {
     417                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     418                                        Utf8StrFmt(GuestSession::tr("Source file \"%s\" is a symbolic link"),
     419                                                   strSource.c_str(), rc));
     420                    rc = VERR_IS_A_SYMLINK;
     421                }
     422                break;
     423
     424            default:
     425                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     426                                    Utf8StrFmt(GuestSession::tr("Source element \"%s\" is not a file"), strSource.c_str()));
     427                rc = VERR_NOT_A_FILE;
     428                break;
     429        }
     430    }
     431
     432    if (RT_FAILURE(rc))
     433        return rc;
     434
     435    rc = mSession->i_fileOpen(srcOpenInfo, srcFile, &rcGuest);
     436    if (RT_FAILURE(rc))
     437    {
     438        switch (rc)
     439        {
     440            case VERR_GSTCTL_GUEST_ERROR:
     441                setProgressErrorMsg(VBOX_E_IPRT_ERROR, GuestFile::i_guestErrorToString(rcGuest));
     442                break;
     443
     444            default:
     445                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     446                                    Utf8StrFmt(GuestSession::tr("Source file \"%s\" could not be opened: %Rrc"),
     447                                               strSource.c_str(), rc));
     448                break;
     449        }
     450    }
     451
     452    if (RT_FAILURE(rc))
     453        return rc;
     454
    546455    char *pszDstFile = NULL;
    547 
    548     RTFSOBJINFO objInfo;
    549     int rc = RTPathQueryInfo(strDest.c_str(), &objInfo, RTFSOBJATTRADD_NOTHING);
     456    RTFSOBJINFO dstObjInfo;
     457    RT_ZERO(dstObjInfo);
     458
     459    bool fSkip = false; /* Whether to skip handling the file. */
     460
    550461    if (RT_SUCCESS(rc))
    551462    {
    552         if (RTFS_IS_FILE(objInfo.Attr.fMode))
     463        rc = RTPathQueryInfo(strDest.c_str(), &dstObjInfo, RTFSOBJATTRADD_NOTHING);
     464        if (RT_SUCCESS(rc))
    553465        {
    554466            if (enmFileCopyFlags & FileCopyFlag_NoReplace)
    555467            {
    556468                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    557                                     Utf8StrFmt(GuestSession::tr("Destination file \"%s\" on host already exists"),
     469                                    Utf8StrFmt(GuestSession::tr("Destination file \"%s\" already exists"), strDest.c_str()));
     470                rc = VERR_ALREADY_EXISTS;
     471            }
     472
     473            if (enmFileCopyFlags & FileCopyFlag_Update)
     474            {
     475                RTTIMESPEC srcModificationTimeTS;
     476                RTTimeSpecSetSeconds(&srcModificationTimeTS, srcObjData.mModificationTime);
     477                if (RTTimeSpecCompare(&srcModificationTimeTS, &dstObjInfo.ModificationTime) <= 0)
     478                {
     479                    setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     480                                        Utf8StrFmt(GuestSession::tr("Destination file \"%s\" has same or newer modification date"),
     481                                                   strDest.c_str()));
     482                    fSkip = true;
     483                }
     484            }
     485        }
     486        else
     487        {
     488            if (rc != VERR_FILE_NOT_FOUND) /* Destination file does not exist (yet)? */
     489                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     490                                    Utf8StrFmt(GuestSession::tr("Destination file lookup for \"%s\" failed: %Rrc"),
    558491                                               strDest.c_str(), rc));
    559                 return VERR_ALREADY_EXISTS;
    560             }
    561 
    562             pszDstFile = RTStrDup(strDest.c_str());
    563         }
    564         else if (RTFS_IS_DIRECTORY(objInfo.Attr.fMode))
     492        }
     493    }
     494
     495    if (fSkip)
     496    {
     497        int rc2 = srcFile->i_closeFile(&rcGuest);
     498        AssertRC(rc2);
     499        return VINF_SUCCESS;
     500    }
     501
     502    if (RT_SUCCESS(rc))
     503    {
     504        if (RTFS_IS_FILE(dstObjInfo.Attr.fMode))
     505        {
     506            if (enmFileCopyFlags & FileCopyFlag_NoReplace)
     507            {
     508                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     509                                    Utf8StrFmt(GuestSession::tr("Destination file \"%s\" already exists"),
     510                                               strDest.c_str(), rc));
     511                rc = VERR_ALREADY_EXISTS;
     512            }
     513            else
     514                pszDstFile = RTStrDup(strDest.c_str());
     515        }
     516        else if (RTFS_IS_DIRECTORY(dstObjInfo.Attr.fMode))
    565517        {
    566518            if (   strDest.endsWith("\\")
     
    578530            {
    579531                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    580                                     Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" on host already exists"),
     532                                    Utf8StrFmt(GuestSession::tr("Destination directory \"%s\" already exists"),
    581533                                               strDest.c_str(), rc));
    582                 return VERR_ALREADY_EXISTS;
    583             }
    584         }
    585         else if (RTFS_IS_SYMLINK(objInfo.Attr.fMode))
     534                rc = VERR_ALREADY_EXISTS;
     535            }
     536        }
     537        else if (RTFS_IS_SYMLINK(dstObjInfo.Attr.fMode))
    586538        {
    587539            if (!(enmFileCopyFlags & FileCopyFlag_FollowLinks))
    588540            {
    589541                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    590                                     Utf8StrFmt(GuestSession::tr("Destination file \"%s\" on the host is a symbolic link"),
     542                                    Utf8StrFmt(GuestSession::tr("Destination file \"%s\" is a symbolic link"),
    591543                                               strDest.c_str(), rc));
    592                 return VERR_IS_A_SYMLINK;
    593             }
    594 
    595             pszDstFile = RTStrDup(strDest.c_str());
    596         }
    597     }
    598     else
     544                rc = VERR_IS_A_SYMLINK;
     545            }
     546            else
     547                pszDstFile = RTStrDup(strDest.c_str());
     548        }
     549        else
     550        {
     551            LogFlowThisFunc(("Object type %RU32 not implemented yet\n", dstObjInfo.Attr.fMode));
     552            rc = VERR_NOT_IMPLEMENTED;
     553        }
     554    }
     555    else if (rc == VERR_FILE_NOT_FOUND)
    599556        pszDstFile = RTStrDup(strDest.c_str());
    600557
    601     if (!pszDstFile)
    602     {
    603         setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No memory to allocate destination file path")));
    604         return VERR_NO_MEMORY;
    605     }
    606 
    607     RTFILE hFile;
    608     rc = RTFileOpen(&hFile, pszDstFile,
    609                     RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
    610     if (RT_FAILURE(rc))
    611     {
    612         setProgressErrorMsg(VBOX_E_IPRT_ERROR,
    613                             Utf8StrFmt(GuestSession::tr("Opening/creating destination file on host \"%s\" failed: %Rrc"),
    614                                        pszDstFile, rc));
    615         return rc;
    616     }
    617 
    618     rc = fileCopyFromEx(strSource, pszDstFile, enmFileCopyFlags, &hFile, 0 /* Offset, unused */, 0 /* Size, unused */);
    619 
    620     int rc2 = RTFileClose(hFile);
     558    if (   RT_SUCCESS(rc)
     559        || rc == VERR_FILE_NOT_FOUND)
     560    {
     561        if (!pszDstFile)
     562        {
     563            setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("No memory to allocate destination file path")));
     564            rc = VERR_NO_MEMORY;
     565        }
     566        else
     567        {
     568            RTFILE hDstFile;
     569            rc = RTFileOpen(&hDstFile, pszDstFile,
     570                            RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE); /** @todo Use the correct open modes! */
     571            if (RT_SUCCESS(rc))
     572            {
     573                LogFlowThisFunc(("Copying '%s' to '%s' (%RI64 bytes) ...\n", strSource.c_str(), pszDstFile, srcObjData.mObjectSize));
     574
     575                rc = fileCopyFromEx(srcFile, &hDstFile, enmFileCopyFlags, 0 /* Offset, unused */, (uint64_t)srcObjData.mObjectSize);
     576
     577                int rc2 = RTFileClose(hDstFile);
     578                AssertRC(rc2);
     579            }
     580            else
     581                setProgressErrorMsg(VBOX_E_IPRT_ERROR,
     582                                    Utf8StrFmt(GuestSession::tr("Opening/creating destination file \"%s\" failed: %Rrc"),
     583                                               pszDstFile, rc));
     584        }
     585    }
     586
     587    RTStrFree(pszDstFile);
     588
     589    int rc2 = srcFile->i_closeFile(&rcGuest);
    621590    AssertRC(rc2);
    622 
    623     if (pszDstFile)
    624         RTStrFree(pszDstFile);
    625591
    626592    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