VirtualBox

Ignore:
Timestamp:
Jul 17, 2020 10:02:58 AM (4 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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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