VirtualBox

Changeset 85371 in vbox for trunk/src/VBox/Main/src-client


Ignore:
Timestamp:
Jul 17, 2020 10:02:58 AM (5 years ago)
Author:
vboxsync
Message:

DnD: Revamped code to simplify / untangle of internal data handling:

  • C-ifying and renaming classes DnDURIList / DnDURIObject -> DnDTransferList / DnDTransferObject
  • Added testcases for DnDTransferList / DnDTransferObject + DnDPath API
  • Reduced memory footprint
  • Greatly simplified / stripped down internal data flow of Main side
  • More (optional) release logging for further diagnosis

Work in progress.

Location:
trunk/src/VBox/Main/src-client
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-client/GuestDnDPrivate.cpp

    r82968 r85371  
    939939    /* cbDataAdd is optional. */
    940940
    941     LogFlowFunc(("cbTotal=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",
    942                  pData->getTotal(), pData->getProcessed(), pData->getRemaining(), cbDataAdd));
     941    LogFlowFunc(("cbExtra=%RU64, cbProcessed=%RU64, cbRemaining=%RU64, cbDataAdd=%RU32\n",
     942                 pData->cbExtra, pData->cbProcessed, pData->getRemaining(), cbDataAdd));
    943943
    944944    if (!pResp)
  • trunk/src/VBox/Main/src-client/GuestDnDSourceImpl.cpp

    r85020 r85371  
    420420    LogFlowThisFunc(("cTransfersPending=%RU32\n", mDataBase.m_cTransfersPending));
    421421
    422     /* Don't allow receiving the actual data until our transfer actually is complete. */
     422    /* Don't allow receiving the actual data until our current transfer is complete. */
    423423    if (mDataBase.m_cTransfersPending)
    424424        return setError(E_FAIL, tr("Current drop operation still in progress"));
    425425
    426     GuestDnDRecvCtx *pCtx = &mData.mRecvCtx;
    427426    HRESULT hr = S_OK;
    428427
    429428    try
    430429    {
    431         bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
    432         if (fHasURIList)
    433         {
    434             LogRel2(("DnD: Drop directory is: %s\n", pCtx->mURI.getDroppedFiles().GetDirAbs()));
    435             int rc2 = pCtx->mURI.toMetaData(aData);
    436             if (RT_FAILURE(rc2))
    437                 hr = E_OUTOFMEMORY;
     430        GuestDnDRecvCtx *pCtx = &mData.mRecvCtx;
     431        if (DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length()))
     432        {
     433            PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles;
     434
     435            const char *pcszDropDirAbs = DnDDroppedFilesGetDirAbs(pDF);
     436            AssertPtr(pcszDropDirAbs);
     437
     438            LogRel2(("DnD: Using drop directory '%s'\n", pcszDropDirAbs));
     439
     440            char  *pszBuf;
     441            size_t cbBuf;
     442            int rc = DnDTransferListGetRootsEx(&pCtx->mTransfer.mList, DNDTRANSFERLISTFMT_NATIVE,
     443                                               pcszDropDirAbs, "\n" /* On all platforms */, &pszBuf, &cbBuf);
     444            if (RT_SUCCESS(rc))
     445            {
     446                aData.resize(cbBuf);
     447                memcpy(&aData.front(), pszBuf, cbBuf);
     448                RTStrFree(pszBuf);
     449            }
     450            else
     451                LogRel(("DnD: Unable to build source root list, rc=%Rrc\n", rc));
    438452        }
    439453        else
    440454        {
    441             const size_t cbData = pCtx->mData.getMeta().getSize();
    442             LogFlowFunc(("cbData=%zu\n", cbData));
    443             if (cbData)
     455            if (pCtx->Meta.cbData)
    444456            {
    445457                /* Copy the data into a safe array of bytes. */
    446                 aData.resize(cbData);
    447                 memcpy(&aData.front(), pCtx->mData.getMeta().getData(), cbData);
     458                aData.resize(pCtx->Meta.cbData);
     459                memcpy(&aData.front(), pCtx->Meta.pvData, pCtx->Meta.cbData);
    448460            }
    449461            else
     
    541553
    542554#ifdef VBOX_WITH_DRAG_AND_DROP_GH
     555/**
     556 * Handles receiving a send data header from the guest.
     557 *
     558 * @returns VBox status code.
     559 * @param   pCtx                Receive context to use.
     560 * @param   pDataHdr            Pointer to send data header from the guest.
     561 */
    543562int GuestDnDSource::i_onReceiveDataHdr(GuestDnDRecvCtx *pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
    544563{
    545     AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
    546     AssertReturn(pDataHdr, VERR_INVALID_POINTER);
    547 
    548     pCtx->mData.setEstimatedSize(pDataHdr->cbTotal, pDataHdr->cbMeta);
    549 
    550     Assert(pCtx->mURI.getObjToProcess() == 0);
    551     pCtx->mURI.reset();
    552     pCtx->mURI.setEstimatedObjects(pDataHdr->cObjects);
     564    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     565    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     566
     567    LogRel2(("DnD: Receiving %RU64 bytes total data (%RU64 bytes meta data, %RU64 objects) from guest ...\n",
     568             pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects));
     569
     570    AssertReturn(pDataHdr->cbTotal >= pDataHdr->cbMeta, VERR_INVALID_PARAMETER);
     571
     572    int rc = pCtx->Meta.resize(pDataHdr->cbMeta);
     573    AssertRCReturn(rc, rc);
     574
     575    pCtx->cbExtra = pDataHdr->cbTotal - pDataHdr->cbMeta;
     576
     577    Assert(pCtx->mTransfer.cObjToProcess == 0); /* Sanity. */
     578    Assert(pCtx->mTransfer.cObjProcessed == 0);
     579
     580    pCtx->mTransfer.reset();
     581
     582    pCtx->mTransfer.cObjToProcess = pDataHdr->cObjects;
    553583
    554584    /** @todo Handle compression type. */
     
    559589}
    560590
     591/**
     592 * Handles receiving a send data block from the guest.
     593 *
     594 * @returns VBox status code.
     595 * @param   pCtx                Receive context to use.
     596 * @param   pSndData            Pointer to send data block from the guest.
     597 */
    561598int GuestDnDSource::i_onReceiveData(GuestDnDRecvCtx *pCtx, PVBOXDNDSNDDATA pSndData)
    562599{
     
    568605    try
    569606    {
    570         GuestDnDData    *pData = &pCtx->mData;
    571         GuestDnDURIData *pURI  = &pCtx->mURI;
     607        GuestDnDTransferRecvData *pTransfer = &pCtx->mTransfer;
    572608
    573609        uint32_t cbData;
     
    593629            pvData  = pSndData->u.v3.pvData;
    594630
    595             /* Note: Data sizes get updated in i_onReceiveDataHdr(). */
    596             cbTotal = pData->getTotal();
    597             cbMeta  = pData->getMeta().getSize();
    598         }
    599         Assert(cbTotal);
     631            /* Note: Data sizes get initialized in i_onReceiveDataHdr().
     632             *       So just use the set values here. */
     633            cbTotal = pCtx->getTotal();
     634            cbMeta  = pCtx->Meta.cbData;
     635        }
    600636
    601637        if (   cbData == 0
    602             || cbData >  cbTotal /* Paranoia */)
    603         {
    604             LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, pData->getTotal()));
     638            || cbData > cbTotal /* Paranoia */)
     639        {
     640            LogFlowFunc(("Incoming data size invalid: cbData=%RU32, cbToProcess=%RU64\n", cbData, cbTotal));
    605641            rc = VERR_INVALID_PARAMETER;
    606642        }
    607         else if (cbTotal < cbMeta)
     643        else if (   cbTotal == 0
     644                 || cbTotal  < cbMeta)
    608645        {
    609646            AssertMsgFailed(("cbTotal (%RU64) is smaller than cbMeta (%RU32)\n", cbTotal, cbMeta));
     
    611648        }
    612649
    613         if (RT_SUCCESS(rc))
    614         {
    615             cbMeta = pData->getMeta().add(pvData, cbData);
    616             LogFlowThisFunc(("cbMetaSize=%zu, cbData=%RU32, cbMeta=%RU32, cbTotal=%RU64\n",
    617                              pData->getMeta().getSize(), cbData, cbMeta, cbTotal));
    618         }
    619 
    620         if (RT_SUCCESS(rc))
    621         {
    622             /*
    623              * (Meta) Data transfer complete?
    624              */
    625             Assert(cbMeta <= pData->getMeta().getSize());
    626             if (cbMeta == pData->getMeta().getSize())
     650        if (RT_FAILURE(rc))
     651            return rc;
     652
     653        cbMeta = pCtx->Meta.add(pvData, cbData);
     654
     655        LogFlowThisFunc(("cbData=%RU32, cbMeta=%RU32, cbTotal=%RU64\n", cbData, cbMeta, cbTotal));
     656
     657        /*
     658         * (Meta) Data transfer complete?
     659         */
     660        Assert(cbMeta <= pCtx->Meta.cbAllocated);
     661        if (cbMeta == pCtx->Meta.cbAllocated)
     662        {
     663            LogRel2(("DnD: Receiving meta data complete\n"));
     664
     665            if (DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length()))
    627666            {
    628                 bool fHasURIList = DnDMIMENeedsDropDir(pCtx->mFmtRecv.c_str(), pCtx->mFmtRecv.length());
    629                 LogFlowThisFunc(("fHasURIList=%RTbool\n", fHasURIList));
    630                 if (fHasURIList)
     667                LogRel2(("DnD: Building transfer list from meta data ...\n"));
     668
     669                rc = DnDTransferListAppendPathsFromBuffer(&pTransfer->mList, DNDTRANSFERLISTFMT_URI,
     670                                                          (const char *)pCtx->Meta.pvData, pCtx->Meta.cbData, DND_PATH_SEPARATOR,
     671                                                          DNDTRANSFERLIST_FLAGS_NONE);
     672                /* Validation. */
     673                if (RT_SUCCESS(rc))
    631674                {
    632                     /* Try parsing the data as URI list. */
    633                     rc = pURI->fromRemoteMetaData(pData->getMeta());
    634                     if (RT_SUCCESS(rc))
    635                     {
    636                         if (mDataBase.m_uProtocolVersion < 3)
    637                             pData->setEstimatedSize(cbTotal, cbMeta);
    638 
    639                         /*
    640                          * Update our process with the data we already received.
    641                          * Note: The total size will consist of the meta data (in pVecData) and
    642                          *       the actual accumulated file/directory data from the guest.
    643                          */
    644                         rc = updateProgress(pData, pCtx->mpResp, (uint32_t)pData->getMeta().getSize());
    645                     }
     675                    uint64_t cRoots = DnDTransferListGetRootCount(&pTransfer->mList);
     676                    if (   cRoots == 0
     677                        || cRoots > pTransfer->cObjToProcess)
     678                        rc = VERR_INVALID_PARAMETER;
    646679                }
    647                 else /* Raw data. */
    648                     rc = updateProgress(pData, pCtx->mpResp, cbData);
     680
     681                if (RT_SUCCESS(rc))
     682                {
     683                    /* Update our process with the data we already received. */
     684                    rc = updateProgress(pCtx, pCtx->mpResp, cbMeta);
     685                    AssertRC(rc);
     686                }
     687
     688                if (RT_FAILURE(rc))
     689                    LogRel(("DnD: Error building transfer list, rc=%Rrc\n", rc));
    649690            }
     691            else /* Raw data. */
     692            {
     693                rc = updateProgress(pCtx, pCtx->mpResp, cbData);
     694                AssertRC(rc);
     695            }
     696
     697            if (RT_FAILURE(rc))
     698                LogRel(("DnD: Error receiving meta data, rc=%Rrc\n", rc));
    650699        }
    651700    }
     
    667716    LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n", pszPath, cbPath, fMode));
    668717
    669     /*
    670      * Sanity checking.
    671      */
    672     if (   !cbPath
    673         || cbPath > RTPATH_MAX)
    674     {
    675         LogFlowFunc(("Path length invalid, bailing out\n"));
    676         return VERR_INVALID_PARAMETER;
    677     }
    678 
    679     int rc = RTStrValidateEncodingEx(pszPath, RTSTR_MAX, 0);
     718    AssertMsgReturn(pCtx->isComplete() == false,
     719                    ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER);
     720
     721    const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj;
     722    const PDNDDROPPEDFILES   pDF  = &pCtx->mTransfer.mDroppedFiles;
     723
     724    int rc = DnDTransferObjectInit(pObj, DNDTRANSFEROBJTYPE_DIRECTORY,
     725                                   DnDDroppedFilesGetDirAbs(pDF), pszPath);
     726    if (RT_SUCCESS(rc))
     727    {
     728        const char *pcszPathAbs = DnDTransferObjectGetSourcePath(pObj);
     729        AssertPtr(pcszPathAbs);
     730
     731        rc = RTDirCreateFullPath(pcszPathAbs, fMode);
     732        if (RT_SUCCESS(rc))
     733        {
     734            pCtx->mTransfer.cObjProcessed++;
     735            if (pCtx->mTransfer.cObjProcessed <= pCtx->mTransfer.cObjToProcess)
     736            {
     737                rc = DnDDroppedFilesAddDir(pDF, pcszPathAbs);
     738            }
     739            else
     740                rc = VERR_TOO_MUCH_DATA;
     741
     742            DnDTransferObjectDestroy(pObj);
     743
     744            if (RT_SUCCESS(rc))
     745                LogRel2(("DnD: Created guest directory '%s' on host\n", pcszPathAbs));
     746        }
     747        else
     748            LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pcszPathAbs, rc));
     749    }
     750
    680751    if (RT_FAILURE(rc))
    681     {
    682         LogFlowFunc(("Path validation failed with %Rrc, bailing out\n", rc));
    683         return VERR_INVALID_PARAMETER;
    684     }
    685 
    686     if (pCtx->mURI.isComplete())
    687     {
    688         LogFlowFunc(("Data transfer already complete, bailing out\n"));
    689         return VERR_INVALID_PARAMETER;
    690     }
    691 
    692     GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    693 
    694     rc = objCtx.createIntermediate(DnDURIObject::Type_Directory);
    695     if (RT_FAILURE(rc))
    696         return rc;
    697 
    698     DnDURIObject *pObj = objCtx.getObj();
    699     AssertPtr(pObj);
    700 
    701     const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
    702     char *pszDir = RTPathJoinA(pszDroppedFilesDir, pszPath);
    703     if (pszDir)
    704     {
    705 #ifdef RT_OS_WINDOWS
    706         RTPathChangeToDosSlashes(pszDir, true /* fForce */);
    707 #else
    708         RTPathChangeToDosSlashes(pszDir, true /* fForce */);
    709 #endif
    710         rc = RTDirCreateFullPath(pszDir, fMode);
    711         if (RT_SUCCESS(rc))
    712         {
    713             pCtx->mURI.processObject(*pObj);
    714 
    715             /* Add for having a proper rollback. */
    716             int rc2 = pCtx->mURI.getDroppedFiles().AddDir(pszDir);
    717             AssertRC(rc2);
    718 
    719             objCtx.reset();
    720             LogRel2(("DnD: Created guest directory '%s' on host\n", pszDir));
    721         }
    722         else
    723             LogRel(("DnD: Error creating guest directory '%s' on host, rc=%Rrc\n", pszDir, rc));
    724 
    725         RTStrFree(pszDir);
    726     }
    727     else
    728          rc = VERR_NO_MEMORY;
     752        LogRel(("DnD: Receiving guest directory '%s' failed with rc=%Rrc\n", pszPath, rc));
    729753
    730754    LogFlowFuncLeaveRC(rc);
     
    732756}
    733757
     758/**
     759 * Receives a file header from the guest.
     760 *
     761 * @returns VBox status code.
     762 * @param   pCtx                Receive context to use.
     763 * @param   pszPath             File path of file to use.
     764 * @param   cbPath              Size (in bytes, including terminator) of file path.
     765 * @param   cbSize              File size (in bytes) to receive.
     766 * @param   fMode               File mode to use.
     767 * @param   fFlags              Additional receive flags; not used yet.
     768 */
    734769int GuestDnDSource::i_onReceiveFileHdr(GuestDnDRecvCtx *pCtx, const char *pszPath, uint32_t cbPath,
    735770                                       uint64_t cbSize, uint32_t fMode, uint32_t fFlags)
    736771{
    737     RT_NOREF(fFlags);
    738772    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    739773    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
     
    742776    /* fFlags are optional. */
    743777
     778    RT_NOREF(fFlags);
     779
    744780    LogFlowFunc(("pszPath=%s, cbPath=%RU32, cbSize=%RU64, fMode=0x%x, fFlags=0x%x\n", pszPath, cbPath, cbSize, fMode, fFlags));
    745781
    746     /*
    747      * Sanity checking.
    748      */
    749     if (   !cbPath
    750         || cbPath > RTPATH_MAX)
    751     {
    752         return VERR_INVALID_PARAMETER;
    753     }
    754 
    755     if (!RTStrIsValidEncoding(pszPath))
    756         return VERR_INVALID_PARAMETER;
    757 
    758     if (cbSize > pCtx->mData.getTotal())
    759     {
    760         AssertMsgFailed(("File size (%RU64) exceeds total size to transfer (%RU64)\n", cbSize, pCtx->mData.getTotal()));
    761         return VERR_INVALID_PARAMETER;
    762     }
    763 
    764     if (pCtx->mURI.getObjToProcess() && pCtx->mURI.isComplete())
    765         return VERR_INVALID_PARAMETER;
     782    AssertMsgReturn(cbSize <= pCtx->cbExtra,
     783                    ("File size (%RU64) exceeds extra size to transfer (%RU64)\n", cbSize, pCtx->cbExtra), VERR_INVALID_PARAMETER);
     784    AssertMsgReturn(   pCtx->isComplete() == false
     785                    && pCtx->mTransfer.cObjToProcess,
     786                    ("Data transfer already complete, bailing out\n"), VERR_INVALID_PARAMETER);
    766787
    767788    int rc = VINF_SUCCESS;
     
    769790    do
    770791    {
    771         GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    772         DnDURIObject *pObj        = objCtx.getObj();
    773 
    774         /*
    775          * Sanity checking.
    776          */
    777         if (pObj)
    778         {
    779             if (    pObj->IsOpen()
    780                 && !pObj->IsComplete())
     792        const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj;
     793
     794        if (    DnDTransferObjectIsOpen(pObj)
     795            && !DnDTransferObjectIsComplete(pObj))
     796        {
     797            AssertMsgFailed(("Object '%s' not complete yet\n", DnDTransferObjectGetSourcePath(pObj)));
     798            rc = VERR_WRONG_ORDER;
     799            break;
     800        }
     801
     802        const PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles;
     803
     804        rc = DnDTransferObjectInit(pObj, DNDTRANSFEROBJTYPE_FILE, DnDDroppedFilesGetDirAbs(pDF), pszPath);
     805        AssertRCBreak(rc);
     806
     807        const char *pcszSource = DnDTransferObjectGetSourcePath(pObj);
     808        AssertPtrBreakStmt(pcszSource, VERR_INVALID_POINTER);
     809
     810        /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
     811        rc = DnDTransferObjectOpen(pObj, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
     812                                   (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR, DNDTRANSFEROBJECT_FLAGS_NONE);
     813        if (RT_FAILURE(rc))
     814        {
     815            LogRel(("DnD: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pcszSource, rc));
     816            break;
     817        }
     818
     819        /* Note: Protocol v1 does not send any file sizes, so always 0. */
     820        if (mDataBase.m_uProtocolVersion >= 2)
     821            rc = DnDTransferObjectSetSize(pObj, cbSize);
     822
     823        /** @todo Unescape path before printing. */
     824        LogRel2(("DnD: Transferring guest file '%s' to host (%RU64 bytes, mode %#x)\n",
     825                 pcszSource, DnDTransferObjectGetSize(pObj), DnDTransferObjectGetMode(pObj)));
     826
     827        /** @todo Set progress object title to current file being transferred? */
     828
     829        if (DnDTransferObjectIsComplete(pObj)) /* 0-byte file? We're done already. */
     830        {
     831            LogRel2(("DnD: Transferring guest file '%s' (0 bytes) to host complete\n", pcszSource));
     832
     833            pCtx->mTransfer.cObjProcessed++;
     834            if (pCtx->mTransfer.cObjProcessed <= pCtx->mTransfer.cObjToProcess)
    781835            {
    782                 AssertMsgFailed(("Object '%s' not complete yet\n", pObj->GetPath().c_str()));
    783                 rc = VERR_WRONG_ORDER;
    784                 break;
     836                /* Add for having a proper rollback. */
     837                rc = DnDDroppedFilesAddFile(pDF, pcszSource);
    785838            }
    786 
    787             if (pObj->IsOpen()) /* File already opened? */
    788             {
    789                 AssertMsgFailed(("Current opened object is '%s', close this first\n", pObj->GetPath().c_str()));
    790                 rc = VERR_WRONG_ORDER;
    791                 break;
    792             }
    793         }
    794         else
    795         {
    796             /*
    797              * Create new intermediate object to work with.
    798              */
    799             rc = objCtx.createIntermediate(DnDURIObject::Type_File);
    800         }
    801 
    802         if (RT_SUCCESS(rc))
    803         {
    804             pObj = objCtx.getObj();
    805             AssertPtr(pObj);
    806 
    807             const char *pszDroppedFilesDir = pCtx->mURI.getDroppedFiles().GetDirAbs();
    808             AssertPtr(pszDroppedFilesDir);
    809 
    810             char pszPathAbs[RTPATH_MAX];
    811             rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszDroppedFilesDir, pszPath);
    812             if (RT_FAILURE(rc))
    813             {
    814                 LogFlowFunc(("Warning: Rebasing current file failed with rc=%Rrc\n", rc));
    815                 break;
    816             }
    817 
    818             rc = pObj->Init(DnDURIObject::Type_File, pszPathAbs);
    819             if (RT_SUCCESS(rc))
    820             {
    821                 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
    822                 rc = pObj->Open(RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
    823                                 (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
    824                 if (RT_SUCCESS(rc))
    825                 {
    826                     /* Add for having a proper rollback. */
    827                     int rc2 = pCtx->mURI.getDroppedFiles().AddFile(pszPathAbs);
    828                     AssertRC(rc2);
    829                 }
    830             }
    831 
    832             if (RT_FAILURE(rc))
    833                 LogRel(("DnD: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pszPathAbs, rc));
    834         }
    835 
    836         if (RT_SUCCESS(rc))
    837         {
    838             /* Note: Protocol v1 does not send any file sizes, so always 0. */
    839             if (mDataBase.m_uProtocolVersion >= 2)
    840                 rc = pObj->SetSize(cbSize);
    841 
    842             /** @todo Unescape path before printing. */
    843             LogRel2(("DnD: Transferring guest file '%s' to host (%RU64 bytes, mode 0x%x)\n",
    844                      pObj->GetPath().c_str(), pObj->GetSize(), pObj->GetMode()));
    845 
    846             /** @todo Set progress object title to current file being transferred? */
    847 
    848             if (pObj->IsComplete()) /* 0-byte file? We're done already. */
    849             {
    850                 LogRel2(("DnD: Transferring guest file '%s' (0 bytes) to host complete\n", pObj->GetPath().c_str()));
    851 
    852                 pCtx->mURI.processObject(*pObj);
    853                 pObj->Close();
    854 
    855                 objCtx.reset();
    856             }
     839            else
     840                rc = VERR_TOO_MUCH_DATA;
     841
     842            DnDTransferObjectDestroy(pObj);
    857843        }
    858844
     
    884870    do
    885871    {
    886         GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObj(0); /** @todo Fill in context ID. */
    887         DnDURIObject *pObj        = objCtx.getObj();
    888 
    889         if (!pObj)
    890         {
    891             LogFlowFunc(("Warning: No current object set\n"));
     872        const PDNDTRANSFEROBJECT pObj = &pCtx->mTransfer.mObj;
     873
     874        if (    DnDTransferObjectIsOpen(pObj)
     875            && !DnDTransferObjectIsComplete(pObj))
     876        {
     877            AssertMsgFailed(("Object '%s' not complete yet\n", DnDTransferObjectGetSourcePath(pObj)));
    892878            rc = VERR_WRONG_ORDER;
    893879            break;
    894880        }
    895881
    896         if (pObj->IsComplete())
    897         {
    898             LogFlowFunc(("Warning: Object '%s' already completed\n", pObj->GetPath().c_str()));
    899             rc = VERR_WRONG_ORDER;
    900             break;
    901         }
    902 
    903         if (!pObj->IsOpen()) /* File opened on host? */
    904         {
    905             LogFlowFunc(("Warning: Object '%s' not opened\n", pObj->GetPath().c_str()));
    906             rc = VERR_WRONG_ORDER;
    907             break;
    908         }
     882        const char *pcszSource = DnDTransferObjectGetSourcePath(pObj);
     883        AssertPtrBreakStmt(pcszSource, VERR_INVALID_POINTER);
    909884
    910885        uint32_t cbWritten;
    911         rc = pObj->Write(pvData, cbData, &cbWritten);
    912         if (RT_SUCCESS(rc))
    913         {
    914             Assert(cbWritten <= cbData);
    915             if (cbWritten < cbData)
    916             {
    917                 LogRel(("DnD: Only written %RU32 of %RU32 bytes of guest file '%s' -- disk full?\n",
    918                         cbWritten, cbData, pObj->GetPath().c_str()));
    919                 rc = VERR_IO_GEN_FAILURE; /** @todo Find a better rc. */
    920             }
    921 
    922             if (RT_SUCCESS(rc))
    923                 rc = updateProgress(&pCtx->mData, pCtx->mpResp, cbWritten);
    924         }
    925         else
    926             LogRel(("DnD: Error writing guest file data for '%s', rc=%Rrc\n", pObj->GetPath().c_str(), rc));
    927 
    928         if (RT_SUCCESS(rc))
    929         {
    930             if (pObj->IsComplete())
    931             {
    932                 /** @todo Sanitize path. */
    933                 LogRel2(("DnD: Transferring guest file '%s' to host complete\n", pObj->GetPath().c_str()));
    934                 pCtx->mURI.processObject(*pObj);
    935                 objCtx.reset();
    936             }
     886        rc = DnDTransferObjectWrite(pObj, pvData, cbData, &cbWritten);
     887        if (RT_FAILURE(rc))
     888            LogRel(("DnD: Error writing guest file data for '%s', rc=%Rrc\n", pcszSource, rc));
     889
     890        Assert(cbWritten <= cbData);
     891        if (cbWritten < cbData)
     892        {
     893            LogRel(("DnD: Only written %RU32 of %RU32 bytes of guest file '%s' -- disk full?\n",
     894                    cbWritten, cbData, pcszSource));
     895            rc = VERR_IO_GEN_FAILURE; /** @todo Find a better rc. */
     896            break;
     897        }
     898
     899        rc = updateProgress(pCtx, pCtx->mpResp, cbWritten);
     900        AssertRCBreak(rc);
     901
     902        if (DnDTransferObjectIsComplete(pObj))
     903        {
     904            LogRel2(("DnD: Transferring guest file '%s' to host complete\n", pcszSource));
     905
     906            pCtx->mTransfer.cObjProcessed++;
     907            if (pCtx->mTransfer.cObjProcessed > pCtx->mTransfer.cObjToProcess)
     908                rc = VERR_TOO_MUCH_DATA;
     909
     910            DnDTransferObjectDestroy(pObj);
    937911        }
    938912
     
    974948     * Reset any old data.
    975949     */
    976     pCtx->mData.reset();
    977     pCtx->mURI.reset();
     950    pCtx->reset();
     951    pCtx->mTransfer.reset();
    978952    pResp->reset();
    979953
     
    10291003        if (fURIData)
    10301004        {
    1031             rc = i_receiveURIData(pCtx, msTimeout);
     1005            rc = i_receiveTransferData(pCtx, msTimeout);
    10321006        }
    10331007        else
     
    11841158}
    11851159
    1186 int GuestDnDSource::i_receiveURIData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout)
     1160int GuestDnDSource::i_receiveTransferData(GuestDnDRecvCtx *pCtx, RTMSINTERVAL msTimeout)
    11871161{
    11881162    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     
    12271201    REGISTER_CALLBACK(GUEST_DND_GH_SND_FILE_DATA);
    12281202
    1229     DnDDroppedFiles &droppedFiles = pCtx->mURI.getDroppedFiles();
     1203    const PDNDDROPPEDFILES pDF = &pCtx->mTransfer.mDroppedFiles;
    12301204
    12311205    do
    12321206    {
    1233         rc = droppedFiles.OpenTemp(0 /* fFlags */);
     1207        rc = DnDDroppedFilesOpenTemp(pDF, 0 /* fFlags */);
    12341208        if (RT_FAILURE(rc))
    12351209        {
    1236             LogRel(("DnD: Opening dropped files directory '%s' on the host failed with rc=%Rrc\n", droppedFiles.GetDirAbs(), rc));
     1210            LogRel(("DnD: Opening dropped files directory '%s' on the host failed with rc=%Rrc\n",
     1211                    DnDDroppedFilesGetDirAbs(pDF), rc));
    12371212            break;
    12381213        }
    12391214
    12401215        /*
    1241          * Receive the URI list.
     1216         * Receive the transfer list.
    12421217         */
    12431218        GuestDnDMsg Msg;
     
    12821257    if (RT_FAILURE(rc))
    12831258    {
    1284         int rc2 = droppedFiles.Rollback();
     1259        int rc2 = DnDDroppedFilesRollback(pDF);
    12851260        if (RT_FAILURE(rc2))
    12861261            LogRel(("DnD: Deleting left over temporary files failed (%Rrc), please remove directory '%s' manually\n",
    1287                     rc2, droppedFiles.GetDirAbs()));
     1262                    rc2, DnDDroppedFilesGetDirAbs(pDF)));
    12881263
    12891264        if (rc == VERR_CANCELLED)
     
    13101285    }
    13111286
    1312     droppedFiles.Close();
     1287    DnDDroppedFilesClose(pDF);
    13131288
    13141289    LogFlowFuncLeaveRC(rc);
     
    14291404
    14301405    /* All data processed? */
    1431     if (pCtx->mData.isComplete())
     1406    if (pCtx->isComplete())
    14321407        fNotify = true;
    14331408
    1434     LogFlowFunc(("cbProcessed=%RU64, cbToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
    1435                  pCtx->mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));
     1409    LogFlowFunc(("cbProcessed=%RU64, cbExtra=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
     1410                 pCtx->cbProcessed, pCtx->cbExtra, fNotify, rcCallback, rc));
    14361411
    14371412    if (fNotify)
     
    16041579
    16051580    /* All data processed? */
    1606     if (   pCtx->mURI.isComplete()
    1607         && pCtx->mData.isComplete())
     1581    if (   pCtx->mTransfer.isComplete()
     1582        && pCtx->isComplete())
    16081583    {
    16091584        fNotify = true;
    16101585    }
    16111586
    1612     LogFlowFunc(("cbProcessed=%RU64, cbToProcess=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
    1613                  pCtx->mData.getProcessed(), pCtx->mData.getTotal(), fNotify, rcCallback, rc));
     1587    LogFlowFunc(("cbProcessed=%RU64, cbExtra=%RU64, fNotify=%RTbool, rcCallback=%Rrc, rc=%Rrc\n",
     1588                 pCtx->cbProcessed, pCtx->cbExtra, fNotify, rcCallback, rc));
    16141589
    16151590    if (fNotify)
  • trunk/src/VBox/Main/src-client/GuestDnDTargetImpl.cpp

    r85020 r85371  
    563563}
    564564
     565/**
     566 * Thread handler function for sending data to the guest.
     567 *
     568 * @param   pTask               Thread task this handler is associated with.
     569 */
    565570/* static */
    566571void GuestDnDTarget::i_sendDataThreadTask(GuestDnDSendDataTask *pTask)
     
    593598
    594599/**
    595  * Initiates a data transfer from the host to the guest. The source is the host whereas the target is the
    596  * guest in this case.
     600 * Initiates a data transfer from the host to the guest.
     601 *
     602 * The source is the host, whereas the target is the guest.
    597603 *
    598604 * @return  HRESULT
    599  * @param   aScreenId
    600  * @param   aFormat
    601  * @param   aData
    602  * @param   aProgress
     605 * @param   aScreenId           Screen ID where this data transfer was initiated from.
     606 * @param   aFormat             Format of data to send. MIME-style.
     607 * @param   aData               Actual data to send.
     608 * @param   aProgress           Where to return the progress object on success.
    603609 */
    604610HRESULT GuestDnDTarget::sendData(ULONG aScreenId, const com::Utf8Str &aFormat, const std::vector<BYTE> &aData,
     
    632638        return hr;
    633639
    634     GuestDnDSendDataTask *pTask = NULL;
    635     GuestDnDSendCtx *pSendCtx = NULL;
     640    GuestDnDSendDataTask *pTask    = NULL;
     641    GuestDnDSendCtx      *pSendCtx = NULL;
    636642
    637643    try
    638644    {
    639         //pSendCtx is passed into SendDataTask where one is deleted in destructor
     645        /* pSendCtx is passed into SendDataTask where one is deleted in destructor. */
    640646        pSendCtx = new GuestDnDSendCtx();
    641         pSendCtx->mpTarget      = this;
    642         pSendCtx->mpResp        = pResp;
    643         pSendCtx->mScreenID     = aScreenId;
    644         pSendCtx->mFmtReq       = aFormat;
    645         pSendCtx->mData.getMeta().add(aData);
     647        pSendCtx->mpTarget  = this;
     648        pSendCtx->mpResp    = pResp;
     649        pSendCtx->mScreenID = aScreenId;
     650        pSendCtx->mFmtReq   = aFormat;
     651
     652        pSendCtx->Meta.add(aData);
    646653
    647654        /* pTask is responsible for deletion of pSendCtx after creating */
     
    757764
    758765/**
    759  * @returns VBox status code that the caller ignores. Not sure if that's
    760  *          intentional or not.
     766 * Main function for sending DnD host data to the guest.
     767 *
     768 * @returns VBox status code.
     769 * @param   pCtx                Send context to use.
     770 * @param   msTimeout           Timeout (in ms) to wait for getting the data sent.
    761771 */
    762772int GuestDnDTarget::i_sendData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout)
     
    776786     * Note: The decision whether we need to build up a file tree and sending
    777787     *       actual file data only depends on the actual formats offered by this target.
    778      *       If the guest does not want an URI list ("text/uri-list") but text ("TEXT" and
     788     *       If the guest does not want a transfer list ("text/uri-list") but text ("TEXT" and
    779789     *       friends) instead, still send the data over to the guest -- the file as such still
    780790     *       is needed on the guest in this case, as the guest then just wants a simple path
    781      *       instead of an URI list (pointing to a file on the guest itself).
     791     *       instead of a transfer list (pointing to a file on the guest itself).
    782792     *
    783793     ** @todo Support more than one format; add a format<->function handler concept. Later. */
     
    787797    if (fHasURIList)
    788798    {
    789         rc = i_sendURIData(pCtx, msTimeout);
     799        rc = i_sendTransferData(pCtx, msTimeout);
    790800    }
    791801    else
     
    800810}
    801811
    802 int GuestDnDTarget::i_sendDataBody(GuestDnDSendCtx *pCtx, GuestDnDData *pData)
    803 {
    804     AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
    805     AssertPtrReturn(pData, VERR_INVALID_POINTER);
     812/**
     813 * Sends the common meta data body to the guest.
     814 *
     815 * @returns VBox status code.
     816 * @param   pCtx                Send context to use.
     817 */
     818int GuestDnDTarget::i_sendMetaDataBody(GuestDnDSendCtx *pCtx)
     819{
     820    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    806821
    807822    /** @todo Add support for multiple HOST_DND_HG_SND_DATA messages in case of more than 64K data! */
    808     if (pData->getMeta().getSize() > _64K)
     823    if (pCtx->Meta.cbData > _64K)
    809824        return VERR_NOT_IMPLEMENTED;
    810825
     826    const uint32_t cbFmt = (uint32_t)pCtx->Meta.strFmt.length() + 1; /* Include terminator. */
     827
     828    LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32\n", cbFmt, pCtx->Meta.cbData));
     829
    811830    GuestDnDMsg Msg;
    812 
    813     LogFlowFunc(("cbFmt=%RU32, cbMeta=%RU32, cbChksum=%RU32\n",
    814                  pData->getFmtSize(), pData->getMeta().getSize(), pData->getChkSumSize()));
    815 
    816831    Msg.setType(HOST_DND_HG_SND_DATA);
    817832    if (mDataBase.m_uProtocolVersion < 3)
    818833    {
    819         Msg.setNextUInt32(pCtx->mScreenID);                                                /* uScreenId */
    820         Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());                   /* pvFormat */
    821         Msg.setNextUInt32(pData->getFmtSize());                                            /* cbFormat */
    822         Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
     834        Msg.setNextUInt32(pCtx->mScreenID);                                 /* uScreenId */
     835        Msg.setNextPointer(pCtx->Meta.strFmt.mutableRaw(), cbFmt);          /* pvFormat */
     836        Msg.setNextUInt32(cbFmt);                                           /* cbFormat */
     837        Msg.setNextPointer(pCtx->Meta.pvData, (uint32_t)pCtx->Meta.cbData); /* pvData */
    823838        /* Fill in the current data block size to send.
    824839         * Note: Only supports uint32_t. */
    825         Msg.setNextUInt32((uint32_t)pData->getMeta().getSize());                           /* cbData */
     840        Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData);                     /* cbData */
    826841    }
    827842    else
    828843    {
    829844        Msg.setNextUInt32(0); /** @todo ContextID not used yet. */
    830         Msg.setNextPointer(pData->getMeta().getDataMutable(), pData->getMeta().getSize()); /* pvData */
    831         Msg.setNextUInt32(pData->getMeta().getSize());                                     /* cbData */
    832         Msg.setNextPointer(pData->getChkSumMutable(), pData->getChkSumSize());             /** @todo pvChecksum; not used yet. */
    833         Msg.setNextUInt32(pData->getChkSumSize());                                         /** @todo cbChecksum; not used yet. */
     845        Msg.setNextPointer(pCtx->Meta.pvData, (uint32_t)pCtx->Meta.cbData); /* pvData */
     846        Msg.setNextUInt32((uint32_t)pCtx->Meta.cbData);                     /* cbData */
     847        Msg.setNextPointer(NULL, 0);                                        /** @todo pvChecksum; not used yet. */
     848        Msg.setNextUInt32(0);                                               /** @todo cbChecksum; not used yet. */
    834849    }
    835850
    836851    int rc = GUESTDNDINST()->hostCall(Msg.getType(), Msg.getCount(), Msg.getParms());
    837852    if (RT_SUCCESS(rc))
    838         rc = updateProgress(pData, pCtx->mpResp, pData->getMeta().getSize());
     853    {
     854        rc = updateProgress(pCtx, pCtx->mpResp, pCtx->Meta.cbData);
     855        AssertRC(rc);
     856    }
    839857
    840858    LogFlowFuncLeaveRC(rc);
     
    842860}
    843861
    844 int GuestDnDTarget::i_sendDataHeader(GuestDnDSendCtx *pCtx, GuestDnDData *pData, GuestDnDURIData *pURIData /* = NULL */)
    845 {
    846     AssertPtrReturn(pCtx,  VERR_INVALID_POINTER);
    847     AssertPtrReturn(pData, VERR_INVALID_POINTER);
    848     /* pURIData is optional. */
     862/**
     863 * Sends the common meta data header to the guest.
     864 *
     865 * @returns VBox status code.
     866 * @param   pCtx                Send context to use.
     867 */
     868int GuestDnDTarget::i_sendMetaDataHeader(GuestDnDSendCtx *pCtx)
     869{
     870    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     871
     872    if (mDataBase.m_uProtocolVersion < 3) /* Protocol < v3 did not support this, skip. */
     873        return VINF_SUCCESS;
    849874
    850875    GuestDnDMsg Msg;
     
    855880    Msg.setNextUInt32(0);                                                /** @todo uFlags; not used yet. */
    856881    Msg.setNextUInt32(pCtx->mScreenID);                                  /* uScreen */
    857     Msg.setNextUInt64(pData->getTotal());                                /* cbTotal */
    858     Msg.setNextUInt32(pData->getMeta().getSize());                       /* cbMeta*/
    859     Msg.setNextPointer(pData->getFmtMutable(), pData->getFmtSize());    /* pvMetaFmt */
    860     Msg.setNextUInt32(pData->getFmtSize());                              /* cbMetaFmt */
    861     Msg.setNextUInt64(pURIData ? pURIData->getObjToProcess() : 0);       /* cObjects */
     882    Msg.setNextUInt64(pCtx->getTotal());                                 /* cbTotal */
     883    Msg.setNextUInt32(pCtx->Meta.cbData);                                /* cbMeta*/
     884    Msg.setNextPointer(unconst(pCtx->Meta.strFmt.c_str()), (uint32_t)pCtx->Meta.strFmt.length() + 1); /* pvMetaFmt */
     885    Msg.setNextUInt32((uint32_t)pCtx->Meta.strFmt.length() + 1);                                      /* cbMetaFmt */
     886    Msg.setNextUInt64(pCtx->mTransfer.cObjToProcess );                   /* cObjects */
    862887    Msg.setNextUInt32(0);                                                /** @todo enmCompression; not used yet. */
    863888    Msg.setNextUInt32(0);                                                /** @todo enmChecksumType; not used yet. */
     
    871896}
    872897
    873 int GuestDnDTarget::i_sendDirectory(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg)
    874 {
    875     AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    876     AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
    877     AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    878 
    879     DnDURIObject *pObj = pObjCtx->getObj();
    880     AssertPtr(pObj);
    881 
    882     RTCString strPath = pObj->GetPath();
    883     if (strPath.isEmpty())
    884         return VERR_INVALID_PARAMETER;
    885     if (strPath.length() >= RTPATH_MAX) /* Note: Maximum is RTPATH_MAX on guest side. */
    886         return VERR_BUFFER_OVERFLOW;
    887 
    888     LogRel2(("DnD: Transferring host directory '%s' to guest\n", strPath.c_str()));
     898int GuestDnDTarget::i_sendDirectory(GuestDnDSendCtx *pCtx, PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg)
     899{
     900    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     901    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
     902
     903    const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj);
     904    AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
     905    const size_t cchPath = RTStrNLen(pcszDstPath, RTPATH_MAX); /* Note: Maximum is RTPATH_MAX on guest side. */
     906    AssertReturn(cchPath, VERR_INVALID_PARAMETER);
     907
     908    LogRel2(("DnD: Transferring host directory '%s' to guest\n", DnDTransferObjectGetSourcePath(pObj)));
    889909
    890910    pMsg->setType(HOST_DND_HG_SND_DIR);
    891911    if (mDataBase.m_uProtocolVersion >= 3)
    892912        pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */
    893     pMsg->setNextString(strPath.c_str());                  /* path */
    894     pMsg->setNextUInt32((uint32_t)(strPath.length() + 1)); /* path length (maximum is RTPATH_MAX on guest side). */
    895     pMsg->setNextUInt32(pObj->GetMode());                  /* mode */
     913    pMsg->setNextString(pcszDstPath);                    /* path */
     914    pMsg->setNextUInt32((uint32_t)(cchPath + 1));        /* path length, including terminator. */
     915    pMsg->setNextUInt32(DnDTransferObjectGetMode(pObj)); /* mode */
    896916
    897917    return VINF_SUCCESS;
    898918}
    899919
    900 int GuestDnDTarget::i_sendFile(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg)
    901 {
    902     AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    903     AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
    904     AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    905 
    906     DnDURIObject *pObj = pObjCtx->getObj();
    907     AssertPtr(pObj);
    908 
    909     RTCString strPathSrc = pObj->GetPath();
    910     if (strPathSrc.isEmpty())
    911         return VERR_INVALID_PARAMETER;
     920/**
     921 * Sends a transfer file to the guest.
     922 *
     923 * @returns VBox status code.
     924 * @param   pCtx
     925 * @param   pObj
     926 * @param   pMsg
     927 */
     928int GuestDnDTarget::i_sendFile(GuestDnDSendCtx *pCtx,
     929                               PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg)
     930{
     931    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     932    AssertPtrReturn(pObj, VERR_INVALID_POINTER);
     933    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
     934
     935    const char *pcszSrcPath = DnDTransferObjectGetSourcePath(pObj);
     936    AssertPtrReturn(pcszSrcPath, VERR_INVALID_POINTER);
     937    const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj);
     938    AssertPtrReturn(pcszDstPath, VERR_INVALID_POINTER);
    912939
    913940    int rc = VINF_SUCCESS;
    914941
    915     LogFlowFunc(("Sending file with %RU32 bytes buffer, using protocol v%RU32 ...\n",
    916                   mData.mcbBlockSize, mDataBase.m_uProtocolVersion));
    917     LogFlowFunc(("strPathSrc=%s, fIsOpen=%RTbool, cbSize=%RU64\n", strPathSrc.c_str(), pObj->IsOpen(), pObj->GetSize()));
    918 
    919     if (!pObj->IsOpen())
    920     {
    921         LogRel2(("DnD: Opening host file '%s' for transferring to guest\n", strPathSrc.c_str()));
    922         rc = pObj->Init(DnDURIObject::Type_File, strPathSrc);
    923         if (RT_SUCCESS(rc))
    924             rc = pObj->Open(RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
    925 
     942    if (!DnDTransferObjectIsOpen(pObj))
     943    {
     944        LogRel2(("DnD: Opening host file '%s' for transferring to guest\n", pcszSrcPath));
     945
     946        rc = DnDTransferObjectOpen(pObj, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE, 0 /* fMode */,
     947                                   DNDTRANSFEROBJECT_FLAGS_NONE);
    926948        if (RT_FAILURE(rc))
    927             LogRel(("DnD: Opening host file '%s' failed, rc=%Rrc\n", strPathSrc.c_str(), rc));
    928     }
     949            LogRel(("DnD: Opening host file '%s' failed, rc=%Rrc\n", pcszSrcPath, rc));
     950    }
     951
     952    if (RT_FAILURE(rc))
     953        return rc;
    929954
    930955    bool fSendData = false;
     
    933958        if (mDataBase.m_uProtocolVersion >= 2)
    934959        {
    935             uint32_t fState = pObjCtx->getState();
    936             if (!(fState & DND_OBJCTX_STATE_HAS_HDR))
     960            if (!(pCtx->mTransfer.mfObjState & DND_OBJ_STATE_HAS_HDR))
    937961            {
     962                const size_t  cchDstPath = RTStrNLen(pcszDstPath, RTPATH_MAX);
     963                const size_t  cbSize     = DnDTransferObjectGetSize(pObj);
     964                const RTFMODE fMode      = DnDTransferObjectGetMode(pObj);
     965
    938966                /*
    939967                 * Since protocol v2 the file header and the actual file contents are
     
    943971                pMsg->setType(HOST_DND_HG_SND_FILE_HDR);
    944972                pMsg->setNextUInt32(0); /** @todo ContextID not used yet. */
    945                 pMsg->setNextString(pObj->GetPath().c_str());                  /* pvName */
    946                 pMsg->setNextUInt32((uint32_t)(pObj->GetPath().length() + 1)); /* cbName */
    947                 pMsg->setNextUInt32(0);                                        /* uFlags */
    948                 pMsg->setNextUInt32(pObj->GetMode());                          /* fMode */
    949                 pMsg->setNextUInt64(pObj->GetSize());                          /* uSize */
    950 
    951                 LogFlowFunc(("Sending file header ...\n"));
    952                 LogRel2(("DnD: Transferring host file '%s' to guest (%RU64 bytes, mode 0x%x)\n",
    953                          pObj->GetPath().c_str(), pObj->GetSize(), pObj->GetMode()));
     973                pMsg->setNextString(pcszDstPath);                    /* pvName */
     974                pMsg->setNextUInt32((uint32_t)(cchDstPath + 1));     /* cbName */
     975                pMsg->setNextUInt32(0);                              /* uFlags */
     976                pMsg->setNextUInt32(fMode);                          /* fMode */
     977                pMsg->setNextUInt64(cbSize);                         /* uSize */
     978
     979                LogRel2(("DnD: Transferring host file '%s' to guest (%zu bytes, mode %#x)\n",
     980                         pcszSrcPath, cbSize, fMode));
    954981
    955982                /** @todo Set progress object title to current file being transferred? */
    956983
    957                 pObjCtx->setState(fState | DND_OBJCTX_STATE_HAS_HDR);
     984                /* Update object state to reflect that we have sent the file header. */
     985                pCtx->mTransfer.mfObjState |= DND_OBJ_STATE_HAS_HDR;
    958986            }
    959987            else
     
    9731001        && fSendData)
    9741002    {
    975         rc = i_sendFileData(pCtx, pObjCtx, pMsg);
     1003        rc = i_sendFileData(pCtx, pObj, pMsg);
    9761004    }
    9771005
    9781006    if (RT_FAILURE(rc))
    979         LogRel(("DnD: Sending host file to guest failed, rc=%Rrc\n", rc));
     1007        LogRel(("DnD: Sending host file '%s' to guest failed, rc=%Rrc\n", pcszSrcPath, rc));
    9801008
    9811009    LogFlowFuncLeaveRC(rc);
     
    9831011}
    9841012
    985 int GuestDnDTarget::i_sendFileData(GuestDnDSendCtx *pCtx, GuestDnDURIObjCtx *pObjCtx, GuestDnDMsg *pMsg)
    986 {
    987     AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
    988     AssertPtrReturn(pObjCtx, VERR_INVALID_POINTER);
    989     AssertPtrReturn(pMsg,    VERR_INVALID_POINTER);
    990 
    991     DnDURIObject *pObj = pObjCtx->getObj();
    992     AssertPtr(pObj);
    993 
    994     AssertPtr(pCtx->mpResp);
     1013int GuestDnDTarget::i_sendFileData(GuestDnDSendCtx *pCtx,
     1014                                   PDNDTRANSFEROBJECT pObj, GuestDnDMsg *pMsg)
     1015{
     1016    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     1017    AssertPtrReturn(pObj, VERR_INVALID_POINTER);
     1018    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
     1019
     1020    AssertPtrReturn(pCtx->mpResp, VERR_WRONG_ORDER);
    9951021
    9961022    /** @todo Don't allow concurrent reads per context! */
    997 
    998     /*
    999      * Start sending stuff.
    1000      */
    10011023
    10021024    /* Set the message type. */
    10031025    pMsg->setType(HOST_DND_HG_SND_FILE_DATA);
     1026
     1027    const char *pcszSrcPath = DnDTransferObjectGetSourcePath(pObj);
     1028    const char *pcszDstPath = DnDTransferObjectGetDestPath(pObj);
    10041029
    10051030    /* Protocol version 1 sends the file path *every* time with a new file chunk.
     
    10071032    if (mDataBase.m_uProtocolVersion <= 1)
    10081033    {
    1009         pMsg->setNextString(pObj->GetPath().c_str());                  /* pvName */
    1010         pMsg->setNextUInt32((uint32_t)(pObj->GetPath().length() + 1)); /* cbName */
     1034        const size_t cchDstPath = RTStrNLen(pcszDstPath, RTPATH_MAX);
     1035
     1036        pMsg->setNextString(pcszDstPath);              /* pvName */
     1037        pMsg->setNextUInt32((uint32_t)cchDstPath + 1); /* cbName */
    10111038    }
    10121039    else if (mDataBase.m_uProtocolVersion >= 2)
    10131040    {
    1014         pMsg->setNextUInt32(0);                                            /** @todo ContextID not used yet. */
    1015     }
    1016 
    1017     uint32_t cbRead = 0;
    1018 
    1019     int rc = pObj->Read(pCtx->mURI.getBufferMutable(), pCtx->mURI.getBufferSize(), &cbRead);
     1041        pMsg->setNextUInt32(0);                        /** @todo ContextID not used yet. */
     1042    }
     1043
     1044    void *pvBuf  = pCtx->mTransfer.pvScratchBuf;
     1045    AssertPtr(pvBuf);
     1046    size_t cbBuf = pCtx->mTransfer.cbScratchBuf;
     1047    Assert(cbBuf);
     1048
     1049    uint32_t cbRead;
     1050
     1051    int rc = DnDTransferObjectRead(pObj, pvBuf, cbBuf, &cbRead);
    10201052    if (RT_SUCCESS(rc))
    10211053    {
    1022         pCtx->mData.addProcessed(cbRead);
    1023         LogFlowFunc(("cbBufSize=%zu, cbRead=%RU32\n", pCtx->mURI.getBufferSize(), cbRead));
     1054        pCtx->addProcessed(cbRead);
     1055
     1056        LogFlowFunc(("cbBufe=%zu, cbRead=%RU32\n", cbBuf, cbRead));
    10241057
    10251058        if (mDataBase.m_uProtocolVersion <= 1)
    10261059        {
    1027             pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
     1060            pMsg->setNextPointer(pvBuf, cbRead);                            /* pvData */
    10281061            pMsg->setNextUInt32(cbRead);                                    /* cbData */
    1029             pMsg->setNextUInt32(pObj->GetMode());                           /* fMode */
     1062            pMsg->setNextUInt32(DnDTransferObjectGetMode(pObj));            /* fMode */
    10301063        }
    10311064        else /* Protocol v2 and up. */
    10321065        {
    1033             pMsg->setNextPointer(pCtx->mURI.getBufferMutable(), cbRead);    /* pvData */
     1066            pMsg->setNextPointer(pvBuf, cbRead);                            /* pvData */
    10341067            pMsg->setNextUInt32(cbRead);                                    /* cbData */
    10351068
     
    10421075        }
    10431076
    1044         if (pObj->IsComplete()) /* Done reading? */
    1045         {
    1046             LogRel2(("DnD: Transferring file '%s' to guest complete\n", pObj->GetPath().c_str()));
    1047             LogFlowFunc(("File '%s' complete\n", pObj->GetPath().c_str()));
    1048 
    1049             /* DnDURIObject::Read() returns VINF_EOF when finished reading the entire fire,
    1050              * but we don't want this here -- so just override this with VINF_SUCCESS. */
     1077        if (DnDTransferObjectIsComplete(pObj)) /* Done reading? */
     1078        {
     1079            LogRel2(("DnD: Transferring host file '%s' to guest complete\n", pcszSrcPath));
     1080
     1081            /* DnDTransferObjectRead() returns VINF_EOF when finished reading the entire file,
     1082             * but we don't want this here -- so just set VINF_SUCCESS. */
    10511083            rc = VINF_SUCCESS;
    10521084        }
    10531085    }
    1054 
    1055     if (RT_FAILURE(rc))
    1056         LogRel(("DnD: Reading from host file '%s' failed, rc=%Rrc\n", pObj->GetPath().c_str(), rc));
     1086    else
     1087        LogRel(("DnD: Reading from host file '%s' failed, rc=%Rrc\n", pcszSrcPath, rc));
    10571088
    10581089    LogFlowFuncLeaveRC(rc);
     
    10961127                GuestDnDMsg *pMsg = new GuestDnDMsg();
    10971128
    1098                 rc = pThis->i_sendURIDataLoop(pCtx, pMsg);
     1129                rc = pThis->i_sendTransferDataLoop(pCtx, pMsg);
    10991130                if (rc == VINF_EOF) /* Transfer complete? */
    11001131                {
     
    12721303}
    12731304
    1274 int GuestDnDTarget::i_sendURIData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout)
     1305/**
     1306 * Main function for sending the actual transfer data (i.e. files + directories) to the guest.
     1307 *
     1308 * @returns VBox status code.
     1309 * @param   pCtx                Send context to use.
     1310 * @param   msTimeout           Timeout (in ms) to use for getting the data sent.
     1311 */
     1312int GuestDnDTarget::i_sendTransferData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout)
    12751313{
    12761314    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
     
    12901328    } while (0)
    12911329
    1292     int rc = pCtx->mURI.init(mData.mcbBlockSize);
     1330    int rc = pCtx->mTransfer.init(mData.mcbBlockSize);
    12931331    if (RT_FAILURE(rc))
    12941332        return rc;
     
    13151353    {
    13161354        /*
    1317          * Extract URI list from current meta data.
     1355         * Extract transfer list from current meta data.
    13181356         */
    1319         GuestDnDData    *pData = &pCtx->mData;
    1320         GuestDnDURIData *pURI  = &pCtx->mURI;
    1321 
    1322         rc = pURI->fromLocalMetaData(pData->getMeta());
     1357        rc = DnDTransferListAppendPathsFromBuffer(&pCtx->mTransfer.mList, DNDTRANSFERLISTFMT_NATIVE,
     1358                                                  (const char *)pCtx->Meta.pvData, pCtx->Meta.cbData, "\n", DNDTRANSFERLIST_FLAGS_NONE);
    13231359        if (RT_FAILURE(rc))
    13241360            break;
    13251361
    1326         LogFlowFunc(("URI root objects: %zu, total bytes (raw data to transfer): %zu\n",
    1327                      pURI->getURIList().GetRootCount(), pURI->getURIList().GetTotalBytes()));
    1328 
    13291362        /*
    1330          * Set the new meta data with the URI list in it.
     1363         * Set the extra data size
    13311364         */
    1332         rc = pData->getMeta().fromURIList(pURI->getURIList());
    1333         if (RT_FAILURE(rc))
    1334             break;
    1335 
    1336         /*
    1337          * Set the estimated data sizes we are going to send.
    1338          * The total size also contains the meta data size.
    1339          */
    1340         const uint32_t cbMeta = pData->getMeta().getSize();
    1341         pData->setEstimatedSize(pURI->getURIList().GetTotalBytes() + cbMeta /* cbTotal */,
    1342                                                                      cbMeta /* cbMeta  */);
    1343 
    1344         /*
    1345          * Set the meta format.
    1346          */
    1347         void    *pvFmt = (void *)pCtx->mFmtReq.c_str();
    1348         uint32_t cbFmt = (uint32_t)pCtx->mFmtReq.length() + 1;           /* Include terminating zero. */
    1349 
    1350         pData->setFmt(pvFmt, cbFmt);
     1365        pCtx->cbExtra = DnDTransferListObjTotalBytes(&pCtx->mTransfer.mList);
    13511366
    13521367        /*
    13531368         * The first message always is the data header. The meta data itself then follows
    1354          * and *only* contains the root elements of an URI list.
     1369         * and *only* contains the root elements of a transfer list.
    13551370         *
    13561371         * After the meta data we generate the messages required to send the
     
    13651380         */
    13661381        if (mDataBase.m_uProtocolVersion >= 3)
    1367             rc = i_sendDataHeader(pCtx, pData, &pCtx->mURI);
     1382            rc = i_sendMetaDataHeader(pCtx);
    13681383
    13691384        /*
     
    13711386         */
    13721387        if (RT_SUCCESS(rc))
    1373             rc = i_sendDataBody(pCtx, pData);
     1388            rc = i_sendMetaDataBody(pCtx);
    13741389
    13751390        if (RT_SUCCESS(rc))
     
    14111426            AssertRC(rc2);
    14121427
     1428            LogRel2(("DnD: Sending transfer data to guest cancelled by user\n"));
     1429
    14131430            rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
    14141431            AssertRC(rc2);
     
    14161433        else if (rc != VERR_GSTDND_GUEST_ERROR) /* Guest-side error are already handled in the callback. */
    14171434        {
     1435            LogRel(("DnD: Sending transfer data to guest failed with rc=%Rrc\n", rc));
    14181436            int rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
    14191437                                                GuestDnDTarget::i_hostErrorToString(rc));
     
    14281446}
    14291447
    1430 int GuestDnDTarget::i_sendURIDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg)
     1448int GuestDnDTarget::i_sendTransferDataLoop(GuestDnDSendCtx *pCtx, GuestDnDMsg *pMsg)
    14311449{
    14321450    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    14331451    AssertPtrReturn(pMsg, VERR_INVALID_POINTER);
    14341452
    1435     int rc = updateProgress(&pCtx->mData, pCtx->mpResp);
     1453    int rc = updateProgress(pCtx, pCtx->mpResp);
    14361454    AssertRC(rc);
    14371455
    1438     if (   pCtx->mData.isComplete()
    1439         && pCtx->mURI.isComplete())
     1456    if (   pCtx->isComplete()
     1457        && pCtx->mTransfer.isComplete())
    14401458    {
    14411459        return VINF_EOF;
    14421460    }
    14431461
    1444     GuestDnDURIObjCtx &objCtx = pCtx->mURI.getObjCurrent();
    1445     if (!objCtx.isValid())
     1462    PDNDTRANSFEROBJECT pObj = DnDTransferListObjGetFirst(&pCtx->mTransfer.mList);
     1463    if (!pObj)
    14461464        return VERR_WRONG_ORDER;
    14471465
    1448     DnDURIObject *pCurObj = objCtx.getObj();
    1449     AssertPtr(pCurObj);
    1450 
    1451     const DnDURIObject::Type enmType = pCurObj->GetType();
    1452 
    1453     LogRel3(("DnD: Processing: srcPath=%s, dstPath=%s, enmType=%RU32, cbSize=%RU32\n",
    1454              pCurObj->GetPath().c_str(), pCurObj->GetPath().c_str(),
    1455              enmType, pCurObj->GetSize()));
    1456 
    1457     if (enmType == DnDURIObject::Type_Directory)
    1458     {
    1459         rc = i_sendDirectory(pCtx, &objCtx, pMsg);
    1460     }
    1461     else if (DnDURIObject::Type_File)
    1462     {
    1463         rc = i_sendFile(pCtx, &objCtx, pMsg);
    1464     }
    1465     else
    1466     {
    1467         AssertMsgFailed(("enmType=%RU32 is not supported for srcPath=%s, dstPath=%s\n",
    1468                          enmType, pCurObj->GetPath().c_str(), pCurObj->GetPath().c_str()));
    1469         rc = VERR_NOT_SUPPORTED;
    1470     }
    1471 
    1472     bool fRemove = false; /* Remove current entry? */
    1473     if (   pCurObj->IsComplete()
     1466    switch (DnDTransferObjectGetType(pObj))
     1467    {
     1468        case DNDTRANSFEROBJTYPE_DIRECTORY:
     1469            rc = i_sendDirectory(pCtx, pObj, pMsg);
     1470            break;
     1471
     1472        case DNDTRANSFEROBJTYPE_FILE:
     1473            rc = i_sendFile(pCtx, pObj, pMsg);
     1474            break;
     1475
     1476        default:
     1477            AssertFailedStmt(rc = VERR_NOT_SUPPORTED);
     1478            break;
     1479    }
     1480
     1481    if (   DnDTransferObjectIsComplete(pObj)
    14741482        || RT_FAILURE(rc))
    1475     {
    1476         fRemove = true;
    1477     }
    1478 
    1479     if (fRemove)
    1480     {
    1481         LogFlowFunc(("Removing \"%s\" from list, rc=%Rrc\n", pCurObj->GetPath().c_str(), rc));
    1482         pCtx->mURI.removeObjCurrent();
    1483     }
     1483        DnDTransferListObjRemoveFirst(&pCtx->mTransfer.mList);
    14841484
    14851485    LogFlowFuncLeaveRC(rc);
     
    14871487}
    14881488
     1489/**
     1490 * Main function for sending raw data (e.g. text, RTF, ...) to the guest.
     1491 *
     1492 * @returns VBox status code.
     1493 * @param   pCtx                Send context to use.
     1494 * @param   msTimeout           Timeout (in ms) to use for getting the data sent.
     1495 */
    14891496int GuestDnDTarget::i_sendRawData(GuestDnDSendCtx *pCtx, RTMSINTERVAL msTimeout)
    14901497{
    14911498    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    14921499    NOREF(msTimeout);
    1493 
    1494     GuestDnDData *pData = &pCtx->mData;
    14951500
    14961501    /** @todo At the moment we only allow sending up to 64K raw data.
    14971502     *        For protocol v1+v2: Fix this by using HOST_DND_HG_SND_MORE_DATA.
    14981503     *        For protocol v3   : Send another HOST_DND_HG_SND_DATA message. */
    1499     if (!pData->getMeta().getSize())
     1504    if (!pCtx->Meta.cbData)
    15001505        return VINF_SUCCESS;
    15011506
    1502     int rc = VINF_SUCCESS;
    1503 
    1504     /*
    1505      * Send the data header first.
    1506      */
    1507     if (mDataBase.m_uProtocolVersion >= 3)
    1508         rc = i_sendDataHeader(pCtx, pData, NULL /* URI list */);
    1509 
    1510     /*
    1511      * Send the (meta) data body.
    1512      */
     1507    int rc = i_sendMetaDataHeader(pCtx);
    15131508    if (RT_SUCCESS(rc))
    1514         rc = i_sendDataBody(pCtx, pData);
     1509        rc = i_sendMetaDataBody(pCtx);
    15151510
    15161511    int rc2;
    15171512    if (RT_FAILURE(rc))
    1518         rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_ERROR, rc,
     1513    {
     1514        LogRel(("DnD: Sending raw data to guest failed with rc=%Rrc\n", rc));
     1515        rc2 = pCtx->mpResp->setProgress(100 /* Percent */, DND_PROGRESS_ERROR, rc,
    15191516                                        GuestDnDTarget::i_hostErrorToString(rc));
     1517    }
    15201518    else
    1521         rc2 = pCtx->mpResp->setProgress(100, DND_PROGRESS_COMPLETE, rc);
     1519        rc2 = pCtx->mpResp->setProgress(100 /* Percent */, DND_PROGRESS_COMPLETE, rc);
    15221520    AssertRC(rc2);
    15231521
     
    15261524}
    15271525
     1526/**
     1527 * Cancels sending DnD data.
     1528 *
     1529 * @returns VBox status code.
     1530 * @param   aVeto               Whether cancelling was vetoed or not.
     1531 *                              Not implemented yet.
     1532 */
    15281533HRESULT GuestDnDTarget::cancel(BOOL *aVeto)
    15291534{
     
    15321537#else /* VBOX_WITH_DRAG_AND_DROP */
    15331538
     1539    LogRel2(("DnD: Sending cancelling request to the guest ...\n"));
     1540
    15341541    int rc = GuestDnDBase::sendCancel();
    15351542
    15361543    if (aVeto)
    1537         *aVeto = FALSE; /** @todo */
     1544        *aVeto = FALSE; /** @todo Impplement vetoing. */
    15381545
    15391546    HRESULT hr = RT_SUCCESS(rc) ? S_OK : VBOX_E_IPRT_ERROR;
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