VirtualBox

Ignore:
Timestamp:
Oct 13, 2015 11:49:33 AM (9 years ago)
Author:
vboxsync
Message:

DnD: Updates.

  • Introduced protocol changelog in DragAndDropSvc.h.
  • Implemented protocol v3 with HOST_DND_HG_SND_DATA_HDR message for doing proper object accounting, among other parameters like checksumming and compression flags.
  • Encapsulated a lot of functionality in class hierarchies.
  • Renamed a lot of functions to make the usage more clear.
  • Various other bugfixes.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuestLib/VBoxGuestR3LibDragAndDrop.cpp

    r58183 r58212  
    4848#include <VBox/HostServices/DragAndDropSvc.h>
    4949
     50using namespace DragAndDropSvc;
     51
    5052#include "VBGLR3Internal.h"
    5153
    52 /* Here all the communication with the host over HGCM is handled platform
    53  * neutral. Also the receiving of URIs content (directory trees and files) is
    54  * done here. So the platform code of the guests, should not take care of that.
    55  *
    56  * Todo:
    57  * - Sending dirs/files in the G->H case
    58  * - Maybe the EOL converting of text MIME types (not fully sure, eventually
    59  *   better done on the host side)
    60  */
    61 
    62 
    6354/*********************************************************************************************************************************
    64 *   Private internal functions                                                                                                   *
     55*    Forward declarations                                                                                                        *
    6556*********************************************************************************************************************************/
    6657
    67 static int vbglR3DnDQueryNextHostMessageType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
     58VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr);
     59
     60/*********************************************************************************************************************************
     61*    Private internal functions                                                                                                  *
     62*********************************************************************************************************************************/
     63
     64static int vbglR3DnDGetNextMsgType(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puMsg, uint32_t *pcParms, bool fWait)
    6865{
    6966    AssertPtrReturn(pCtx,    VERR_INVALID_POINTER);
     
    7168    AssertPtrReturn(pcParms, VERR_INVALID_POINTER);
    7269
    73     DragAndDropSvc::VBOXDNDNEXTMSGMSG Msg;
     70    VBOXDNDNEXTMSGMSG Msg;
    7471    RT_ZERO(Msg);
    7572    Msg.hdr.result      = VERR_WRONG_ORDER;
    7673    Msg.hdr.u32ClientID = pCtx->uClientID;
    77     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG;
     74    Msg.hdr.u32Function = GUEST_DND_GET_NEXT_HOST_MSG;
    7875    Msg.hdr.cParms      = 3;
    7976
    80     Msg.msg.SetUInt32(0);
    81     Msg.num_parms.SetUInt32(0);
    82     Msg.block.SetUInt32(fWait ? 1 : 0);
     77    Msg.uMsg.SetUInt32(0);
     78    Msg.cParms.SetUInt32(0);
     79    Msg.fBlock.SetUInt32(fWait ? 1 : 0);
    8380
    8481    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    8885        if (RT_SUCCESS(rc))
    8986        {
    90             rc = Msg.msg.GetUInt32(puMsg);         AssertRC(rc);
    91             rc = Msg.num_parms.GetUInt32(pcParms); AssertRC(rc);
    92         }
    93     }
    94 
    95     return rc;
    96 }
    97 
    98 static int vbglR3DnDHGProcessActionMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    99                                            uint32_t  uMsg,
    100                                            uint32_t *puScreenId,
    101                                            uint32_t *puX,
    102                                            uint32_t *puY,
    103                                            uint32_t *puDefAction,
    104                                            uint32_t *puAllActions,
    105                                            char     *pszFormats,
    106                                            uint32_t  cbFormats,
    107                                            uint32_t *pcbFormatsRecv)
     87            rc = Msg.uMsg.GetUInt32(puMsg);         AssertRC(rc);
     88            rc = Msg.cParms.GetUInt32(pcParms); AssertRC(rc);
     89        }
     90    }
     91
     92    return rc;
     93}
     94
     95/** @todo r=andy Clean up the parameter list. */
     96static int vbglR3DnDHGRecvAction(PVBGLR3GUESTDNDCMDCTX pCtx,
     97                                 uint32_t  uMsg,
     98                                 uint32_t *puScreenId,
     99                                 uint32_t *puX,
     100                                 uint32_t *puY,
     101                                 uint32_t *puDefAction,
     102                                 uint32_t *puAllActions,
     103                                 char     *pszFormats,
     104                                 uint32_t  cbFormats,
     105                                 uint32_t *pcbFormatsRecv)
    108106{
    109107    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
     
    117115    AssertPtrReturn(pcbFormatsRecv, VERR_INVALID_POINTER);
    118116
    119     DragAndDropSvc::VBOXDNDHGACTIONMSG Msg;
     117    VBOXDNDHGACTIONMSG Msg;
    120118    RT_ZERO(Msg);
     119    Msg.hdr.result      = VERR_WRONG_ORDER;
    121120    Msg.hdr.u32ClientID = pCtx->uClientID;
    122121    Msg.hdr.u32Function = uMsg;
     
    151150}
    152151
    153 static int vbglR3DnDHGProcessLeaveMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     152static int vbglR3DnDHGRecvLeave(PVBGLR3GUESTDNDCMDCTX pCtx)
    154153{
    155154    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    156155
    157     DragAndDropSvc::VBOXDNDHGLEAVEMSG Msg;
     156    VBOXDNDHGLEAVEMSG Msg;
    158157    RT_ZERO(Msg);
    159158    Msg.hdr.u32ClientID = pCtx->uClientID;
    160     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_LEAVE;
     159    Msg.hdr.u32Function = HOST_DND_HG_EVT_LEAVE;
    161160    Msg.hdr.cParms      = 0;
    162161
     
    168167}
    169168
    170 static int vbglR3DnDHGProcessCancelMessage(PVBGLR3GUESTDNDCMDCTX pCtx)
     169static int vbglR3DnDHGRecvCancel(PVBGLR3GUESTDNDCMDCTX pCtx)
    171170{
    172171    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    173172
    174     DragAndDropSvc::VBOXDNDHGCANCELMSG Msg;
     173    VBOXDNDHGCANCELMSG Msg;
    175174    RT_ZERO(Msg);
     175    Msg.hdr.result      = VERR_WRONG_ORDER;
    176176    Msg.hdr.u32ClientID = pCtx->uClientID;
    177     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_EVT_CANCEL;
     177    Msg.hdr.u32Function = HOST_DND_HG_EVT_CANCEL;
    178178    Msg.hdr.cParms      = 0;
    179179
     
    185185}
    186186
    187 static int vbglR3DnDHGProcessSendDirMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    188                                             char     *pszDirname,
    189                                             uint32_t  cbDirname,
    190                                             uint32_t *pcbDirnameRecv,
    191                                             uint32_t *pfMode)
     187static int vbglR3DnDHGRecvDir(PVBGLR3GUESTDNDCMDCTX pCtx,
     188                              char     *pszDirname,
     189                              uint32_t  cbDirname,
     190                              uint32_t *pcbDirnameRecv,
     191                              uint32_t *pfMode)
    192192{
    193193    AssertPtrReturn(pCtx,           VERR_INVALID_POINTER);
     
    197197    AssertPtrReturn(pfMode,         VERR_INVALID_POINTER);
    198198
    199     DragAndDropSvc::VBOXDNDHGSENDDIRMSG Msg;
     199    VBOXDNDHGSENDDIRMSG Msg;
    200200    RT_ZERO(Msg);
     201    Msg.hdr.result      = VERR_WRONG_ORDER;
    201202    Msg.hdr.u32ClientID = pCtx->uClientID;
    202     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DIR;
     203    Msg.hdr.u32Function = HOST_DND_HG_SND_DIR;
    203204    Msg.hdr.cParms      = 3;
    204205
    205206    Msg.pvName.SetPtr(pszDirname, cbDirname);
    206     Msg.cbName.SetUInt32(0);
     207    Msg.cbName.SetUInt32(cbDirname);
    207208    Msg.fMode.SetUInt32(0);
    208209
     
    223224}
    224225
    225 static int vbglR3DnDHGProcessSendFileMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    226                                              char                 *pszFilename,
    227                                              uint32_t              cbFilename,
    228                                              uint32_t             *pcbFilenameRecv,
    229                                              void                 *pvData,
    230                                              uint32_t              cbData,
    231                                              uint32_t             *pcbDataRecv,
    232                                              uint32_t             *pfMode)
     226static int vbglR3DnDHGRecvFileData(PVBGLR3GUESTDNDCMDCTX pCtx,
     227                                   char                 *pszFilename,
     228                                   uint32_t              cbFilename,
     229                                   uint32_t             *pcbFilenameRecv,
     230                                   void                 *pvData,
     231                                   uint32_t              cbData,
     232                                   uint32_t             *pcbDataRecv,
     233                                   uint32_t             *pfMode)
    233234{
    234235    AssertPtrReturn(pCtx,            VERR_INVALID_POINTER);
     
    241242    AssertPtrReturn(pfMode,          VERR_INVALID_POINTER);
    242243
    243     DragAndDropSvc::VBOXDNDHGSENDFILEDATAMSG Msg;
     244    VBOXDNDHGSENDFILEDATAMSG Msg;
    244245    RT_ZERO(Msg);
     246    Msg.hdr.result      = VERR_WRONG_ORDER;
    245247    Msg.hdr.u32ClientID = pCtx->uClientID;
    246     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA;
     248    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_DATA;
    247249
    248250    if (pCtx->uProtocol <= 1)
    249251    {
    250252        Msg.u.v1.pvName.SetPtr(pszFilename, cbFilename);
    251         Msg.u.v1.cbName.SetUInt32(cbFilename);
     253        Msg.u.v1.cbName.SetUInt32(0);
    252254        Msg.u.v1.pvData.SetPtr(pvData, cbData);
    253         Msg.u.v1.cbData.SetUInt32(cbData);
     255        Msg.u.v1.cbData.SetUInt32(0);
    254256        Msg.u.v1.fMode.SetUInt32(0);
    255257
    256258        Msg.hdr.cParms = 5;
    257259    }
    258     else
    259     {
    260         Msg.u.v2.uContext.SetUInt32(0); /** @todo Not used yet. */
     260    else if (pCtx->uProtocol == 2)
     261    {
     262        Msg.u.v2.uContext.SetUInt32(0);
    261263        Msg.u.v2.pvData.SetPtr(pvData, cbData);
    262264        Msg.u.v2.cbData.SetUInt32(cbData);
     
    264266        Msg.hdr.cParms = 3;
    265267    }
     268    else if (pCtx->uProtocol >= 3)
     269    {
     270        Msg.u.v3.uContext.SetUInt32(0);
     271        Msg.u.v3.pvData.SetPtr(pvData, cbData);
     272        Msg.u.v3.cbData.SetUInt32(0);
     273        Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     274        Msg.u.v3.cbChecksum.SetUInt32(0);
     275
     276        Msg.hdr.cParms = 5;
     277    }
     278    else
     279        AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
    266280
    267281    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    280294                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
    281295            }
    282             else
    283             {
     296            else if (pCtx->uProtocol == 2)
     297            {
     298                /** @todo Context ID not used yet. */
    284299                rc = Msg.u.v2.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
    285300                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
    286301            }
    287         }
    288     }
    289 
    290     LogFlowFuncLeaveRC(rc);
    291     return rc;
    292 }
    293 
    294 static int vbglR3DnDHGProcessSendFileHdrMessage(PVBGLR3GUESTDNDCMDCTX  pCtx,
    295                                                 char                  *pszFilename,
    296                                                 uint32_t               cbFilename,
    297                                                 uint32_t              *puFlags,
    298                                                 uint32_t              *pfMode,
    299                                                 uint64_t              *pcbTotal)
     302            else if (pCtx->uProtocol >= 3)
     303            {
     304                /** @todo Context ID not used yet. */
     305                rc = Msg.u.v3.cbData.GetUInt32(pcbDataRecv);     AssertRC(rc);
     306                AssertReturn(cbData     >= *pcbDataRecv,     VERR_TOO_MUCH_DATA);
     307                /** @todo Add checksum support. */
     308            }
     309            else
     310                AssertMsgFailed(("Protocol %RU32 not implemented\n", pCtx->uProtocol));
     311        }
     312    }
     313
     314    return rc;
     315}
     316
     317static int vbglR3DnDHGRecvFileHdr(PVBGLR3GUESTDNDCMDCTX  pCtx,
     318                                  char                  *pszFilename,
     319                                  uint32_t               cbFilename,
     320                                  uint32_t              *puFlags,
     321                                  uint32_t              *pfMode,
     322                                  uint64_t              *pcbTotal)
    300323{
    301324    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     
    306329    AssertReturn(pcbTotal,       VERR_INVALID_POINTER);
    307330
    308     DragAndDropSvc::VBOXDNDHGSENDFILEHDRMSG Msg;
     331    VBOXDNDHGSENDFILEHDRMSG Msg;
    309332    RT_ZERO(Msg);
     333    Msg.hdr.result      = VERR_WRONG_ORDER;
    310334    Msg.hdr.u32ClientID = pCtx->uClientID;
    311     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR;
     335    Msg.hdr.u32Function = HOST_DND_HG_SND_FILE_HDR;
    312336
    313337    int rc;
     
    348372}
    349373
    350 static int vbglR3DnDHGProcessURIMessages(PVBGLR3GUESTDNDCMDCTX   pCtx,
    351                                          void                  **ppvData,
    352                                          uint32_t                cbData,
    353                                          size_t                 *pcbDataRecv)
    354 {
    355     AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
    356     AssertPtrReturn(ppvData,     VERR_INVALID_POINTER);
    357     AssertReturn(cbData,         VERR_INVALID_PARAMETER);
    358     AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
     374static int vbglR3DnDHGRecvURIData(PVBGLR3GUESTDNDCMDCTX pCtx, DnDDroppedFiles *pDroppedFiles)
     375{
     376    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     377    AssertPtrReturn(pDroppedFiles, VERR_INVALID_POINTER);
    359378
    360379    /*
    361      * Allocate chunk buffer.
     380     * Allocate temporary chunk buffer.
    362381     */
    363     uint32_t cbChunkMax = _64K; /** @todo Make this configurable? */
     382    uint32_t cbChunkMax = pCtx->cbMaxChunkSize;
    364383    void *pvChunk = RTMemAlloc(cbChunkMax);
    365384    if (!pvChunk)
    366385        return VERR_NO_MEMORY;
    367     uint32_t cbChunkRead = 0;
     386    uint32_t cbChunkRead   = 0;
    368387
    369388    uint64_t cbFileSize    = 0; /* Total file size (in bytes). */
     
    373392     * Create and query the (unique) drop target directory in the user's temporary directory.
    374393     */
    375     DnDDroppedFiles droppedFiles;
    376     int rc = droppedFiles.OpenTemp(0 /* fFlags */);
     394    int rc = pDroppedFiles->OpenTemp(0 /* fFlags */);
    377395    if (RT_FAILURE(rc))
    378396    {
     
    381399    }
    382400
    383     const char *pszDropDir = droppedFiles.GetDirAbs();
     401    const char *pszDropDir = pDroppedFiles->GetDirAbs();
    384402    AssertPtr(pszDropDir);
    385403
     
    387405     * Enter the main loop of retieving files + directories.
    388406     */
    389     DnDURIList lstURI;
    390407    DnDURIObject objFile(DnDURIObject::File);
    391408
     
    399416        uint32_t uNextMsg;
    400417        uint32_t cNextParms;
    401         rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
     418        rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fWait */);
    402419        if (RT_SUCCESS(rc))
    403420        {
     
    406423            switch (uNextMsg)
    407424            {
    408                 case DragAndDropSvc::HOST_DND_HG_SND_DIR:
     425                case HOST_DND_HG_SND_DIR:
    409426                {
    410                     rc = vbglR3DnDHGProcessSendDirMessage(pCtx,
    411                                                           szPathName,
    412                                                           sizeof(szPathName),
    413                                                           &cbPathName,
    414                                                           &fMode);
     427                    rc = vbglR3DnDHGRecvDir(pCtx,
     428                                            szPathName,
     429                                            sizeof(szPathName),
     430                                            &cbPathName,
     431                                            &fMode);
    415432                    LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
    416433                                 szPathName, cbPathName, fMode, rc));
     
    426443                        rc = RTDirCreate(pszPathAbs, fCreationMode, 0);
    427444                        if (RT_SUCCESS(rc))
    428                             rc = droppedFiles.AddDir(pszPathAbs);
     445                            rc = pDroppedFiles->AddDir(pszPathAbs);
    429446
    430447                        RTStrFree(pszPathAbs);
     
    434451                    break;
    435452                }
    436                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR:
    437                 case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     453                case HOST_DND_HG_SND_FILE_HDR:
     454                case HOST_DND_HG_SND_FILE_DATA:
    438455                {
    439                     if (uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR)
     456                    if (uNextMsg == HOST_DND_HG_SND_FILE_HDR)
    440457                    {
    441                         rc = vbglR3DnDHGProcessSendFileHdrMessage(pCtx,
    442                                                                   szPathName,
    443                                                                   sizeof(szPathName),
    444                                                                   &fFlags,
    445                                                                   &fMode,
    446                                                                   &cbFileSize);
    447                         LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
     458                        rc = vbglR3DnDHGRecvFileHdr(pCtx,
     459                                                    szPathName,
     460                                                    sizeof(szPathName),
     461                                                    &fFlags,
     462                                                    &fMode,
     463                                                    &cbFileSize);
     464                        LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR: "
     465                                     "szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
    448466                                     szPathName, fFlags, fMode, cbFileSize, rc));
    449467                    }
    450468                    else
    451469                    {
    452                         rc = vbglR3DnDHGProcessSendFileMessage(pCtx,
    453                                                                szPathName,
    454                                                                sizeof(szPathName),
    455                                                                &cbPathName,
    456                                                                pvChunk,
    457                                                                cbChunkMax,
    458                                                                &cbChunkRead,
    459                                                                &fMode);
    460                         LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
     470                        rc = vbglR3DnDHGRecvFileData(pCtx,
     471                                                     szPathName,
     472                                                     sizeof(szPathName),
     473                                                     &cbPathName,
     474                                                     pvChunk,
     475                                                     cbChunkMax,
     476                                                     &cbChunkRead,
     477                                                     &fMode);
     478
     479                        LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: "
    461480                                     "szPathName=%s, cbPathName=%RU32, cbChunkRead=%RU32, fMode=0x%x, rc=%Rrc\n",
    462481                                     szPathName, cbPathName, cbChunkRead, fMode, rc));
     
    464483
    465484                    if (   RT_SUCCESS(rc)
    466                         && (   uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_HDR
    467                              /* Protocol v1 always sends the file name, so opening the file every time. */
     485                        && (   uNextMsg == HOST_DND_HG_SND_FILE_HDR
     486                            /* Protocol v1 always sends the file name, so opening the file every time. */
    468487                            || pCtx->uProtocol <= 1)
    469488                       )
     
    493512                                if (RT_SUCCESS(rc))
    494513                                {
    495                                     rc = droppedFiles.AddFile(strPathAbs.c_str());
     514                                    rc = pDroppedFiles->AddFile(strPathAbs.c_str());
    496515                                    if (RT_SUCCESS(rc))
    497516                                    {
     
    513532
    514533                    if (   RT_SUCCESS(rc)
    515                         && uNextMsg == DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA)
     534                        && uNextMsg == HOST_DND_HG_SND_FILE_DATA)
    516535                    {
    517536                        bool fClose = false;
     
    521540                        if (RT_SUCCESS(rc))
    522541                        {
     542                            LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
     543                                         "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n",
     544                                         cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize));
     545
    523546                            if (pCtx->uProtocol >= 2)
    524547                            {
    525548                                /* Data transfer complete? Close the file. */
    526549                                fClose = objFile.IsComplete();
     550
     551                                /* Only since protocol v2 we know the file size upfront. */
     552                                Assert(cbFileWritten <= cbFileSize);
    527553                            }
    528554                            else
     
    530556
    531557                            cbFileWritten += cbChunkWritten;
    532                             Assert(cbFileWritten <= cbFileSize);
    533558                        }
    534559
     
    541566                    break;
    542567                }
    543                 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
     568                case HOST_DND_HG_EVT_CANCEL:
    544569                {
    545                     rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     570                    rc = vbglR3DnDHGRecvCancel(pCtx);
    546571                    if (RT_SUCCESS(rc))
    547572                        rc = VERR_CANCELLED;
     
    568593        rc = VINF_SUCCESS;
    569594
    570     /* Delete chunk buffer again. */
     595    /* Delete temp buffer again. */
    571596    if (pvChunk)
    572597        RTMemFree(pvChunk);
     
    576601    if (RT_FAILURE(rc))
    577602    {
    578         int rc2 = droppedFiles.Rollback();
     603        objFile.Close();
     604
     605        int rc2 = pDroppedFiles->Rollback();
    579606        AssertRC(rc2); /* Not fatal, don't report back to host. */
    580607    }
    581608    else
    582609    {
    583         /*
    584          * Now we need to transform the URI list which came from the host into
    585          * an URI list which also has the final "Dropped Files" directory as a prefix
    586          * for each URI entry.
    587          *
    588          * So patch the old drop data with the new drop directory to let the drop
    589          * target on the guest can find the files later.
    590          */
    591         void  *pvURIData = *ppvData;
    592         size_t cbURIData = *pcbDataRecv;
    593 
    594         rc = lstURI.RootFromURIData(pvURIData, cbURIData, 0 /* fFlags */);
    595         if (RT_SUCCESS(rc))
    596         {
    597             /* Cleanup the old data and write the new data back to the event. */
    598             RTMemFree(pvURIData);
    599 
    600             RTCString strData = lstURI.RootToString(pszDropDir);
    601             Assert(!strData.isEmpty());
    602             LogFlowFunc(("New URI list now has %zu bytes (formerly %RU32 bytes)\n", strData.length() + 1, cbURIData));
    603 
    604             pvURIData = RTStrDupN(strData.c_str(), strData.length());
    605             if (pvURIData)
    606             {
    607                 cbURIData = strData.length() + 1;
    608             }
    609             else
    610                 rc = VERR_NO_MEMORY;
    611         }
    612 
    613         if (RT_SUCCESS(rc))
    614         {
    615             *ppvData     = pvURIData;
    616             *pcbDataRecv = cbURIData;
    617         }
    618 
    619610        /** @todo Compare the URI list with the dirs/files we really transferred. */
     611        /** @todo Implement checksum verification, if any. */
    620612    }
    621613
     
    625617     * by the client's drag'n drop operation lateron.
    626618     */
    627     int rc2 = droppedFiles.Reset(false /* fRemoveDropDir */);
     619    int rc2 = pDroppedFiles->Reset(false /* fRemoveDropDir */);
    628620    if (RT_FAILURE(rc2)) /* Not fatal, don't report back to host. */
    629621        LogFlowFunc(("Closing dropped files directory failed with %Rrc\n", rc2));
     
    633625}
    634626
    635 static int vbglR3DnDHGProcessDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    636                                                  uint32_t *puScreenId,
    637                                                  char     *pszFormat,
    638                                                  uint32_t  cbFormat,
    639                                                  uint32_t *pcbFormatRecv,
    640                                                  void     *pvData,
    641                                                  uint32_t  cbData,
    642                                                  uint32_t *pcbDataTotal)
    643 {
    644     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    645     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    646     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    647     AssertReturn(cbFormat,         VERR_INVALID_PARAMETER);
    648     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    649     AssertPtrReturn(pvData,        VERR_INVALID_POINTER);
    650     AssertReturn(cbData,           VERR_INVALID_PARAMETER);
    651     AssertPtrReturn(pcbDataTotal,  VERR_INVALID_POINTER);
    652 
    653     DragAndDropSvc::VBOXDNDHGSENDDATAMSG Msg;
     627static int vbglR3DnDHGRecvDataRaw(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
     628                                  void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
     629{
     630    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     631    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     632    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
     633    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
     634    /* pcbDataRecv is optional. */
     635
     636    int rc;
     637
     638    LogFlowFunc(("pvDate=%p, cbData=%RU32\n", pvData, cbData));
     639
     640    VBOXDNDHGSENDDATAMSG Msg;
    654641    RT_ZERO(Msg);
     642    Msg.hdr.result      = VERR_WRONG_ORDER;
    655643    Msg.hdr.u32ClientID = pCtx->uClientID;
    656     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_DATA;
    657     Msg.hdr.cParms      = 5;
    658 
     644    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA;
     645
     646    do
     647    {
     648        uint32_t cbDataRecv;
     649
     650        if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     651        {
     652            Msg.hdr.cParms  = 5;
     653
     654            Msg.u.v1.uScreenId.SetUInt32(0);
     655            Msg.u.v1.pvFormat.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     656            Msg.u.v1.cbFormat.SetUInt32(0);
     657            Msg.u.v1.pvData.SetPtr(pvData, cbData);
     658            Msg.u.v1.cbData.SetUInt32(0);
     659
     660            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     661            if (RT_SUCCESS(rc))
     662            {
     663                rc = Msg.hdr.result;
     664                if (   RT_SUCCESS(rc)
     665                    || rc == VERR_BUFFER_OVERFLOW)
     666                {
     667                    rc = Msg.u.v1.uScreenId.GetUInt32(&pDataHdr->uScreenId);
     668                    AssertRC(rc);
     669
     670                    /*
     671                     * In case of VERR_BUFFER_OVERFLOW get the data sizes required
     672                     * for the format + data blocks.
     673                     */
     674                    uint32_t cbFormatRecv;
     675                    rc = Msg.u.v1.cbFormat.GetUInt32(&cbFormatRecv);
     676                    AssertRC(rc);
     677                    if (cbFormatRecv >= pDataHdr->cbMetaFmt)
     678                    {
     679                        rc = VERR_TOO_MUCH_DATA;
     680                        break;
     681                    }
     682
     683                    rc = Msg.u.v1.cbData.GetUInt32(&cbDataRecv);
     684                    AssertRC(rc);
     685                    if (cbDataRecv >= pDataHdr->cbMeta)
     686                    {
     687                        rc = VERR_TOO_MUCH_DATA;
     688                        break;
     689                    }
     690
     691                    pDataHdr->cbMetaFmt = cbFormatRecv;
     692                }
     693            }
     694
     695            if (RT_FAILURE(rc))
     696                break;
     697        }
     698        else /* Protocol v3 and up. */
     699        {
     700            Msg.hdr.cParms = 5;
     701
     702            Msg.u.v3.uContext.SetUInt32(0);
     703            Msg.u.v3.pvData.SetPtr(pvData, cbData);
     704            Msg.u.v3.cbData.SetUInt32(0);
     705            Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     706            Msg.u.v3.cbChecksum.SetUInt32(0);
     707
     708            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     709            if (RT_SUCCESS(rc))
     710            {
     711                rc = Msg.hdr.result;
     712                if (RT_SUCCESS(rc))
     713                {
     714                    rc = Msg.u.v3.cbData.GetUInt32(&cbDataRecv);
     715                    AssertRC(rc);
     716                }
     717
     718                /** @todo Use checksum for validating the received data. */
     719            }
     720
     721            if (RT_FAILURE(rc))
     722                break;
     723        }
     724
     725        if (pcbDataRecv)
     726            *pcbDataRecv = cbDataRecv;
     727
     728    } while (0);
     729
     730    LogFlowFuncLeaveRC(rc);
     731    return rc;
     732}
     733
     734static int vbglR3DnDHGRecvDataHdr(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr)
     735{
     736    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     737    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     738
     739    Assert(pCtx->uProtocol >= 3); /* Only for protocol v3 and up. */
     740
     741    VBOXDNDHGSENDDATAHDRMSG Msg;
     742    RT_ZERO(Msg);
     743    Msg.hdr.result      = VERR_WRONG_ORDER;
     744    Msg.hdr.u32ClientID = pCtx->uClientID;
     745    Msg.hdr.u32Function = HOST_DND_HG_SND_DATA_HDR;
     746    Msg.hdr.cParms      = 12;
     747
     748    Msg.uContext.SetUInt32(0);
     749    Msg.uFlags.SetUInt32(0);
    659750    Msg.uScreenId.SetUInt32(0);
    660     Msg.pvFormat.SetPtr(pszFormat, cbFormat);
    661     Msg.cFormat.SetUInt32(0);
     751    Msg.cbTotal.SetUInt64(0);
     752    Msg.cbMeta.SetUInt32(0);
     753    Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     754    Msg.cbMetaFmt.SetUInt32(0);
     755    Msg.cObjects.SetUInt64(0);
     756    Msg.enmCompression.SetUInt32(0);
     757    Msg.enmChecksumType.SetUInt32(0);
     758    Msg.pvChecksum.SetPtr(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
     759    Msg.cbChecksum.SetUInt32(0);
     760
     761    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     762    if (RT_SUCCESS(rc))
     763    {
     764        rc = Msg.hdr.result;
     765        if (RT_SUCCESS(rc))
     766        {
     767            /* Msg.uContext not needed here. */
     768            Msg.uFlags.GetUInt32(&pDataHdr->uFlags);
     769            Msg.uScreenId.GetUInt32(&pDataHdr->uScreenId);
     770            Msg.cbTotal.GetUInt64(&pDataHdr->cbTotal);
     771            Msg.cbMeta.GetUInt32(&pDataHdr->cbMeta);
     772            Msg.cbMetaFmt.GetUInt32(&pDataHdr->cbMetaFmt);
     773            Msg.cObjects.GetUInt64(&pDataHdr->cObjects);
     774            Msg.enmCompression.GetUInt32(&pDataHdr->enmCompression);
     775            Msg.enmChecksumType.GetUInt32((uint32_t *)&pDataHdr->enmChecksumType);
     776            Msg.cbChecksum.GetUInt32(&pDataHdr->cbChecksum);
     777        }
     778    }
     779
     780    LogFlowFuncLeaveRC(rc);
     781    return rc;
     782}
     783
     784/** @todo Deprecated function; will be removed. */
     785static int vbglR3DnDHGRecvMoreData(PVBGLR3GUESTDNDCMDCTX pCtx,
     786                                   void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
     787{
     788    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
     789    AssertPtrReturn(pvData,      VERR_INVALID_POINTER);
     790    AssertReturn(cbData,         VERR_INVALID_PARAMETER);
     791    AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
     792
     793    VBOXDNDHGSENDMOREDATAMSG Msg;
     794    RT_ZERO(Msg);
     795    Msg.hdr.result      = VERR_WRONG_ORDER;
     796    Msg.hdr.u32ClientID = pCtx->uClientID;
     797    Msg.hdr.u32Function = HOST_DND_HG_SND_MORE_DATA;
     798    Msg.hdr.cParms      = 2;
     799
    662800    Msg.pvData.SetPtr(pvData, cbData);
    663801    Msg.cbData.SetUInt32(0);
     
    670808            || rc == VERR_BUFFER_OVERFLOW)
    671809        {
    672             rc = Msg.uScreenId.GetUInt32(puScreenId);  AssertRC(rc);
    673 
    674             /*
    675              * In case of VERR_BUFFER_OVERFLOW get the data sizes required
    676              * for the format + data blocks.
    677              */
    678             rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    679             rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
    680 
    681             AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
    682             AssertReturn(cbData   >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
    683         }
    684     }
    685 
    686     return rc;
    687 }
    688 
    689 static int vbglR3DnDHGProcessMoreDataMessageInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    690                                                      void     *pvData,
    691                                                      uint32_t  cbData,
    692                                                      uint32_t *pcbDataTotal)
    693 {
    694     AssertPtrReturn(pCtx,         VERR_INVALID_POINTER);
    695     AssertPtrReturn(pvData,       VERR_INVALID_POINTER);
    696     AssertReturn(cbData,          VERR_INVALID_PARAMETER);
    697     AssertPtrReturn(pcbDataTotal, VERR_INVALID_POINTER);
    698 
    699     DragAndDropSvc::VBOXDNDHGSENDMOREDATAMSG Msg;
    700     RT_ZERO(Msg);
    701     Msg.hdr.u32ClientID = pCtx->uClientID;
    702     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA;
    703     Msg.hdr.cParms      = 2;
    704 
    705     Msg.pvData.SetPtr(pvData, cbData);
    706     Msg.cbData.SetUInt32(0);
    707 
    708     int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    709     if (RT_SUCCESS(rc))
    710     {
    711         rc = Msg.hdr.result;
    712         if (   RT_SUCCESS(rc)
    713             || rc == VERR_BUFFER_OVERFLOW)
    714         {
    715             rc = Msg.cbData.GetUInt32(pcbDataTotal); AssertRC(rc);
    716             AssertReturn(cbData >= *pcbDataTotal, VERR_TOO_MUCH_DATA);
    717         }
    718     }
    719     return rc;
    720 }
    721 
    722 static int vbglR3DnDHGProcessSendDataMessageLoop(PVBGLR3GUESTDNDCMDCTX pCtx,
    723                                                  uint32_t *puScreenId,
    724                                                  char     *pszFormat,
    725                                                  uint32_t  cbFormat,
    726                                                  uint32_t *pcbFormatRecv,
    727                                                  void    **ppvData,
    728                                                  uint32_t  cbData,
    729                                                  size_t   *pcbDataRecv)
    730 {
    731     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    732     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    733     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    734     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    735     AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
    736     /* pcbDataRecv is optional. */
    737 
    738     uint32_t cbDataReq = 0;
    739     int rc = vbglR3DnDHGProcessDataMessageInternal(pCtx,
    740                                                    puScreenId,
    741                                                    pszFormat,
    742                                                    cbFormat,
    743                                                    pcbFormatRecv,
    744                                                    *ppvData,
    745                                                    cbData,
    746                                                    &cbDataReq);
    747     uint32_t cbDataTotal = cbDataReq;
    748     void *pvData = *ppvData;
    749 
    750     LogFlowFunc(("HOST_DND_HG_SND_DATA cbDataReq=%RU32, rc=%Rrc\n", cbDataTotal, rc));
    751 
    752     while (rc == VERR_BUFFER_OVERFLOW)
    753     {
    754         uint32_t uNextMsg;
    755         uint32_t cNextParms;
    756         rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uNextMsg, &cNextParms, false);
    757         if (RT_SUCCESS(rc))
    758         {
    759             switch(uNextMsg)
    760             {
    761                 case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
     810            rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
     811            AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
     812        }
     813    }
     814    return rc;
     815}
     816
     817static int vbglR3DnDHGRecvDataLoop(PVBGLR3GUESTDNDCMDCTX pCtx, PVBOXDNDSNDDATAHDR pDataHdr,
     818                                   void **ppvData, uint64_t *pcbData)
     819{
     820    AssertPtrReturn(pCtx,     VERR_INVALID_POINTER);
     821    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     822    AssertPtrReturn(ppvData,  VERR_INVALID_POINTER);
     823    AssertPtrReturn(pcbData,  VERR_INVALID_POINTER);
     824
     825    int rc;
     826    uint32_t cbDataRecv;
     827
     828    if (pCtx->uProtocol < 3) /* For VBox < 5.0.8. */
     829    {
     830        uint64_t cbDataTmp = pCtx->cbMaxChunkSize;
     831        void    *pvDataTmp = RTMemAlloc(cbDataTmp);
     832
     833        if (!cbDataTmp)
     834            return VERR_NO_MEMORY;
     835
     836        /**
     837         * Protocols < v3 contain the header information in every HOST_DND_HG_SND_DATA
     838         * message, so do the actual retrieving immediately.
     839         *
     840         * Also, the initial implementation used VERR_BUFFER_OVERFLOW as a return code to
     841         * indicate that there will be more data coming in after the initial data chunk. There
     842         * was no way of telling the total data size upfront (in form of a header or some such),
     843         * so also handle this case to not break backwards compatibility.
     844         */
     845        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr, pvDataTmp, pCtx->cbMaxChunkSize, &cbDataRecv);
     846
     847        /* See comment above. */
     848        while (rc == VERR_BUFFER_OVERFLOW)
     849        {
     850            uint32_t uNextMsg;
     851            uint32_t cNextParms;
     852            rc = vbglR3DnDGetNextMsgType(pCtx, &uNextMsg, &cNextParms, false /* fBlock */);
     853            if (RT_SUCCESS(rc))
     854            {
     855                switch(uNextMsg)
    762856                {
    763                     /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
    764                      *               Instead send as many URI entries as possible per chunk and add those entries
    765                      *               to our to-process list for immediata processing. Repeat the step after processing then. */
    766                     LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU32 -> %RU32\n", cbDataReq, cbDataReq + cbData));
    767                     pvData = RTMemRealloc(*ppvData, cbDataTotal + cbData);
    768                     if (!pvData)
     857                    case HOST_DND_HG_SND_MORE_DATA:
    769858                    {
    770                         rc = VERR_NO_MEMORY;
     859                        /** @todo r=andy Don't use reallocate here; can go wrong with *really* big URI lists.
     860                         *               Instead send as many URI entries as possible per chunk and add those entries
     861                         *               to our to-process list for immediata processing. Repeat the step after processing then. */
     862                        LogFlowFunc(("HOST_DND_HG_SND_MORE_DATA cbDataTotal: %RU64 -> %RU64\n",
     863                                     cbDataTmp, cbDataTmp + pCtx->cbMaxChunkSize));
     864                        void *pvDataNew = RTMemRealloc(pvDataTmp, cbDataTmp + pCtx->cbMaxChunkSize);
     865                        if (!pvDataNew)
     866                        {
     867                            rc = VERR_NO_MEMORY;
     868                            break;
     869                        }
     870
     871                        pvDataTmp = pvDataNew;
     872
     873                        uint8_t *pvDataOff = (uint8_t *)pvDataTmp + cbDataTmp;
     874                        rc = vbglR3DnDHGRecvMoreData(pCtx, pvDataOff, pCtx->cbMaxChunkSize, &cbDataRecv);
     875                        if (   RT_SUCCESS(rc)
     876                            || rc == VERR_BUFFER_OVERFLOW) /* Still can return VERR_BUFFER_OVERFLOW. */
     877                        {
     878                            cbDataTmp += cbDataRecv;
     879                        }
    771880                        break;
    772881                    }
    773                     rc = vbglR3DnDHGProcessMoreDataMessageInternal(pCtx,
    774                                                                    &((char *)pvData)[cbDataTotal],
    775                                                                    cbData,
    776                                                                    &cbDataReq);
    777                     cbDataTotal += cbDataReq;
    778                     break;
     882                    case HOST_DND_HG_EVT_CANCEL:
     883                    default:
     884                    {
     885                        rc = vbglR3DnDHGRecvCancel(pCtx);
     886                        if (RT_SUCCESS(rc))
     887                            rc = VERR_CANCELLED;
     888                        break;
     889                    }
    779890                }
    780                 case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    781                 default:
     891            }
     892        }
     893
     894        if (RT_SUCCESS(rc))
     895        {
     896            /* There was no way of telling the total data size upfront
     897             * (in form of a header or some such), so set the total data size here. */
     898            pDataHdr->cbTotal = cbDataTmp;
     899
     900            *ppvData = pvDataTmp;
     901            *pcbData = cbDataTmp;
     902        }
     903        else
     904            RTMemFree(pvDataTmp);
     905    }
     906    else /* Protocol v3 and up. Since VBox 5.0.8. */
     907    {
     908        rc = vbglR3DnDHGRecvDataHdr(pCtx, pDataHdr);
     909        if (RT_SUCCESS(rc))
     910        {
     911            LogFlowFunc(("cbMeta=%RU32\n", pDataHdr->cbMeta));
     912            if (pDataHdr->cbMeta)
     913            {
     914                uint64_t cbDataTmp = 0;
     915                void    *pvDataTmp = RTMemAlloc(pDataHdr->cbMeta);
     916                if (!pvDataTmp)
     917                    rc = VERR_NO_MEMORY;
     918
     919                if (RT_SUCCESS(rc))
    782920                {
    783                     rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     921                    uint8_t *pvDataOff = (uint8_t *)pvDataTmp;
     922                    while (cbDataTmp < pDataHdr->cbMeta)
     923                    {
     924                        rc = vbglR3DnDHGRecvDataRaw(pCtx, pDataHdr,
     925                                                    pvDataOff, RT_MIN(pDataHdr->cbMeta - cbDataTmp, pCtx->cbMaxChunkSize),
     926                                                    &cbDataRecv);
     927                        if (RT_SUCCESS(rc))
     928                        {
     929                            LogFlowFunc(("cbDataRecv=%RU32, cbDataTmp=%RU64\n", cbDataRecv, cbDataTmp));
     930                            Assert(cbDataTmp + cbDataRecv <= pDataHdr->cbMeta);
     931                            cbDataTmp += cbDataRecv;
     932                            pvDataOff += cbDataRecv;
     933                        }
     934                        else
     935                            break;
     936                    }
     937
    784938                    if (RT_SUCCESS(rc))
    785                         rc = VERR_CANCELLED;
    786                     break;
     939                    {
     940                        Assert(cbDataTmp == pDataHdr->cbMeta);
     941
     942                        LogFlowFunc(("Received %RU64 bytes of data\n", cbDataTmp));
     943
     944                        *ppvData = pvDataTmp;
     945                        *pcbData = cbDataTmp;
     946                    }
     947                    else
     948                        RTMemFree(pvDataTmp);
    787949                }
    788950            }
    789         }
    790     }
    791 
    792     if (RT_SUCCESS(rc))
    793     {
    794         *ppvData         = pvData;
    795         if (pcbDataRecv)
    796             *pcbDataRecv = cbDataTotal;
     951            else
     952            {
     953                *ppvData = NULL;
     954                *pcbData = 0;
     955            }
     956        }
    797957    }
    798958
     
    801961}
    802962
    803 static int vbglR3DnDHGProcessSendDataMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    804                                              uint32_t  *puScreenId,
    805                                              char      *pszFormat,
    806                                              uint32_t   cbFormat,
    807                                              uint32_t  *pcbFormatRecv,
    808                                              void     **ppvData,
    809                                              uint32_t   cbData,
    810                                              size_t    *pcbDataRecv)
    811 {
    812     AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
    813     AssertPtrReturn(puScreenId,    VERR_INVALID_POINTER);
    814     AssertPtrReturn(pszFormat,     VERR_INVALID_POINTER);
    815     AssertPtrReturn(pcbFormatRecv, VERR_INVALID_POINTER);
    816     AssertPtrReturn(ppvData,       VERR_INVALID_POINTER);
    817 
    818     int rc = vbglR3DnDHGProcessSendDataMessageLoop(pCtx,
    819                                                    puScreenId,
    820                                                    pszFormat,
    821                                                    cbFormat,
    822                                                    pcbFormatRecv,
    823                                                    ppvData,
    824                                                    cbData,
    825                                                    pcbDataRecv);
    826     if (RT_SUCCESS(rc))
    827     {
    828         /* Check if this is an URI event. If so, let VbglR3 do all the actual
     963/** @todo Replace the parameters (except pCtx) with PVBOXDNDSNDDATAHDR. Later. */
     964/** @todo Hand in the DnDURIList + DnDDroppedFiles objects so that this function
     965 *        can fill it directly instead of passing huge blobs of data around. */
     966static int vbglR3DnDHGRecvDataMain(PVBGLR3GUESTDNDCMDCTX  pCtx,
     967                                   uint32_t              *puScreenId,
     968                                   char                 **ppszFormat,
     969                                   uint32_t              *pcbFormat,
     970                                   void                 **ppvData,
     971                                   uint32_t              *pcbData)
     972{
     973    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
     974    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
     975    AssertPtrReturn(ppszFormat, VERR_INVALID_POINTER);
     976    AssertPtrReturn(pcbFormat,  VERR_INVALID_POINTER);
     977    AssertPtrReturn(ppvData,    VERR_INVALID_POINTER);
     978    AssertPtrReturn(pcbData,    VERR_INVALID_POINTER);
     979
     980    VBOXDNDDATAHDR dataHdr; /** @todo See todo above. */
     981    RT_ZERO(dataHdr);
     982
     983    dataHdr.cbMetaFmt = _64K;  /** @todo Make this configurable? */
     984    dataHdr.pvMetaFmt = RTMemAlloc(dataHdr.cbMetaFmt);
     985    if (!dataHdr.pvMetaFmt)
     986        return VERR_NO_MEMORY;
     987
     988    DnDURIList lstURI;
     989    DnDDroppedFiles droppedFiles;
     990
     991    void *pvData;    /** @todo See todo above. */
     992    uint64_t cbData; /** @todo See todo above. */
     993
     994    int rc = vbglR3DnDHGRecvDataLoop(pCtx, &dataHdr, &pvData, &cbData);
     995    if (RT_SUCCESS(rc))
     996    {
     997        /**
     998         * Check if this is an URI event. If so, let VbglR3 do all the actual
    829999         * data transfer + file/directory creation internally without letting
    8301000         * the caller know.
    8311001         *
    8321002         * This keeps the actual (guest OS-)dependent client (like VBoxClient /
    833          * VBoxTray) small by not having too much redundant code. */
    834         AssertPtr(pcbFormatRecv);
    835         if (DnDMIMEHasFileURLs(pszFormat, *pcbFormatRecv))
    836             rc = vbglR3DnDHGProcessURIMessages(pCtx,
    837                                                ppvData,
    838                                                cbData,
    839                                                pcbDataRecv);
    840         if (RT_FAILURE(rc))
    841         {
    842             int rc2 = VbglR3DnDHGSetProgress(pCtx, DragAndDropSvc::DND_PROGRESS_ERROR, 100 /* Percent */, rc);
    843             AssertRC(rc2);
    844         }
     1003         * VBoxTray) small by not having too much redundant code.
     1004         */
     1005        Assert(dataHdr.cbMetaFmt);
     1006        AssertPtr(dataHdr.pvMetaFmt);
     1007        if (DnDMIMEHasFileURLs((char *)dataHdr.pvMetaFmt, dataHdr.cbMetaFmt))
     1008        {
     1009            AssertPtr(pvData);
     1010            Assert(cbData);
     1011            rc = lstURI.RootFromURIData(pvData, cbData, 0 /* fFlags */);
     1012            if (RT_SUCCESS(rc))
     1013                rc = vbglR3DnDHGRecvURIData(pCtx, &droppedFiles);
     1014
     1015            if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */
     1016            {
     1017                if (pvData)
     1018                {
     1019                    /* Reuse data buffer to fill in the transformed URI file list. */
     1020                    RTMemFree(pvData);
     1021                    pvData = NULL;
     1022                }
     1023
     1024                RTCString strData = lstURI.RootToString(droppedFiles.GetDirAbs());
     1025                Assert(!strData.isEmpty());
     1026
     1027                cbData = strData.length() + 1;
     1028                LogFlowFunc(("URI list has %zu bytes\n", cbData));
     1029
     1030                pvData = RTMemAlloc(cbData);
     1031                if (pvData)
     1032                {
     1033                    memcpy(pvData, strData.c_str(), cbData);
     1034                }
     1035                else
     1036                    rc =  VERR_NO_MEMORY;
     1037            }
     1038        }
     1039        else /* Raw data. */
     1040        {
     1041            const uint32_t cbDataRaw = dataHdr.cbMetaFmt;
     1042            if (cbData >= cbDataRaw)
     1043            {
     1044                if (cbDataRaw)
     1045                    memcpy(pvData, dataHdr.pvMetaFmt, cbDataRaw);
     1046                cbData = cbDataRaw;
     1047            }
     1048            else
     1049                rc = VERR_BUFFER_OVERFLOW;
     1050        }
     1051    }
     1052
     1053    if (   RT_FAILURE(rc)
     1054        && rc != VERR_CANCELLED)
     1055    {
     1056        if (dataHdr.pvMetaFmt)
     1057            RTMemFree(dataHdr.pvMetaFmt);
     1058        if (pvData)
     1059            RTMemFree(pvData);
     1060
     1061        int rc2 = VbglR3DnDHGSendProgress(pCtx, DND_PROGRESS_ERROR, 100 /* Percent */, rc);
     1062        AssertRC(rc2);
     1063    }
     1064    else if (RT_SUCCESS(rc))
     1065    {
     1066        *ppszFormat = (char *)dataHdr.pvMetaFmt;
     1067        *pcbFormat  =         dataHdr.cbMetaFmt;
     1068        *ppvData    = pvData;
     1069        *pcbData    = cbData;
    8451070    }
    8461071
     
    8491074}
    8501075
    851 static int vbglR3DnDGHProcessRequestPendingMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    852                                                    uint32_t *puScreenId)
     1076static int vbglR3DnDGHRecvPending(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t *puScreenId)
    8531077{
    8541078    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    8551079    AssertPtrReturn(puScreenId, VERR_INVALID_POINTER);
    8561080
    857     DragAndDropSvc::VBOXDNDGHREQPENDINGMSG Msg;
     1081    VBOXDNDGHREQPENDINGMSG Msg;
    8581082    RT_ZERO(Msg);
     1083    Msg.hdr.result      = VERR_WRONG_ORDER;
    8591084    Msg.hdr.u32ClientID = pCtx->uClientID;
    860     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_REQ_PENDING;
     1085    Msg.hdr.u32Function = HOST_DND_GH_REQ_PENDING;
    8611086    Msg.hdr.cParms      = 1;
    8621087
     
    8761101}
    8771102
    878 static int vbglR3DnDGHProcessDroppedMessage(PVBGLR3GUESTDNDCMDCTX pCtx,
    879                                             char     *pszFormat,
    880                                             uint32_t  cbFormat,
    881                                             uint32_t *pcbFormatRecv,
    882                                             uint32_t *puAction)
     1103static int vbglR3DnDGHRecvDropped(PVBGLR3GUESTDNDCMDCTX pCtx,
     1104                                  char     *pszFormat,
     1105                                  uint32_t  cbFormat,
     1106                                  uint32_t *pcbFormatRecv,
     1107                                  uint32_t *puAction)
    8831108{
    8841109    AssertPtrReturn(pCtx,          VERR_INVALID_POINTER);
     
    8881113    AssertPtrReturn(puAction,      VERR_INVALID_POINTER);
    8891114
    890     DragAndDropSvc::VBOXDNDGHDROPPEDMSG Msg;
     1115    VBOXDNDGHDROPPEDMSG Msg;
    8911116    RT_ZERO(Msg);
     1117    Msg.hdr.result      = VERR_WRONG_ORDER;
    8921118    Msg.hdr.u32ClientID = pCtx->uClientID;
    893     Msg.hdr.u32Function = DragAndDropSvc::HOST_DND_GH_EVT_DROPPED;
     1119    Msg.hdr.u32Function = HOST_DND_GH_EVT_DROPPED;
    8941120    Msg.hdr.cParms      = 3;
    8951121
    8961122    Msg.pvFormat.SetPtr(pszFormat, cbFormat);
    897     Msg.cFormat.SetUInt32(0);
     1123    Msg.cbFormat.SetUInt32(0);
    8981124    Msg.uAction.SetUInt32(0);
    8991125
     
    9041130        if (RT_SUCCESS(rc))
    9051131        {
    906             rc = Msg.cFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
    907             rc = Msg.uAction.GetUInt32(puAction);      AssertRC(rc);
     1132            rc = Msg.cbFormat.GetUInt32(pcbFormatRecv); AssertRC(rc);
     1133            rc = Msg.uAction.GetUInt32(puAction);       AssertRC(rc);
    9081134
    9091135            AssertReturn(cbFormat >= *pcbFormatRecv, VERR_TOO_MUCH_DATA);
     
    9441170        {
    9451171            /* Set the default protocol version to use. */
    946             pCtx->uProtocol = 2;
     1172            pCtx->uProtocol = 3;
    9471173
    9481174            Assert(Info.u32ClientID);
     
    9671193            {
    9681194                fSupportsConnectReq = RTStrVersionCompare(pszHostVersion, "5.0") >= 0;
     1195                LogFlowFunc(("pszHostVersion=%s, fSupportsConnectReq=%RTbool\n", pszHostVersion, fSupportsConnectReq));
    9691196                VbglR3GuestPropReadValueFree(pszHostVersion);
    9701197            }
     
    9721199            VbglR3GuestPropDisconnect(uGuestPropSvcClientID);
    9731200        }
     1201
     1202        if (RT_FAILURE(rc2))
     1203            LogFlowFunc(("Retrieving host version failed with rc=%Rrc\n", rc2));
    9741204    }
    9751205
     
    9811211         *       does not implement this command.
    9821212         */
    983         DragAndDropSvc::VBOXDNDCONNECTMSG Msg;
     1213        VBOXDNDCONNECTMSG Msg;
    9841214        RT_ZERO(Msg);
    9851215        Msg.hdr.result      = VERR_WRONG_ORDER;
    9861216        Msg.hdr.u32ClientID = pCtx->uClientID;
    987         Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_CONNECT;
     1217        Msg.hdr.u32Function = GUEST_DND_CONNECT;
    9881218        Msg.hdr.cParms      = 2;
    9891219
     
    10051235        pCtx->uProtocol = 1; /* Fall back to protocol version 1 (< VBox 5.0). */
    10061236
     1237    pCtx->cbMaxChunkSize = _64K; /** @todo Use a scratch buffer on the heap? */
     1238
    10071239    LogFlowFunc(("uClient=%RU32, uProtocol=%RU32, rc=%Rrc\n", pCtx->uClientID, pCtx->uProtocol, rc));
    10081240    return rc;
     
    10241256}
    10251257
    1026 VBGLR3DECL(int) VbglR3DnDProcessNextMessage(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
     1258VBGLR3DECL(int) VbglR3DnDRecvNextMsg(PVBGLR3GUESTDNDCMDCTX pCtx, CPVBGLR3DNDHGCMEVENT pEvent)
    10271259{
    10281260    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
    10291261    AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
    10301262
    1031     uint32_t       uMsg       = 0;
    1032     uint32_t       uNumParms  = 0;
    1033     const uint32_t ccbFormats = _64K;
    1034     const uint32_t ccbData    = _64K;
    1035     int rc = vbglR3DnDQueryNextHostMessageType(pCtx, &uMsg, &uNumParms,
    1036                                                true /* fWait */);
     1263    uint32_t       uMsg      = 0;
     1264    uint32_t       uNumParms = 0;
     1265
     1266    const uint32_t cbDataMax   = pCtx->cbMaxChunkSize;
     1267    const uint32_t cbFormatMax = pCtx->cbMaxChunkSize;
     1268
     1269    int rc = vbglR3DnDGetNextMsgType(pCtx, &uMsg, &uNumParms, true /* fWait */);
    10371270    if (RT_SUCCESS(rc))
    10381271    {
     
    10411274        switch(uMsg)
    10421275        {
    1043             case DragAndDropSvc::HOST_DND_HG_EVT_ENTER:
    1044             case DragAndDropSvc::HOST_DND_HG_EVT_MOVE:
    1045             case DragAndDropSvc::HOST_DND_HG_EVT_DROPPED:
    1046             {
    1047                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
     1276            case HOST_DND_HG_EVT_ENTER:
     1277            case HOST_DND_HG_EVT_MOVE:
     1278            case HOST_DND_HG_EVT_DROPPED:
     1279            {
     1280                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
    10481281                if (!pEvent->pszFormats)
    10491282                    rc = VERR_NO_MEMORY;
    10501283
    10511284                if (RT_SUCCESS(rc))
    1052                     rc = vbglR3DnDHGProcessActionMessage(pCtx,
    1053                                                          uMsg,
    1054                                                          &pEvent->uScreenId,
    1055                                                          &pEvent->u.a.uXpos,
    1056                                                          &pEvent->u.a.uYpos,
    1057                                                          &pEvent->u.a.uDefAction,
    1058                                                          &pEvent->u.a.uAllActions,
    1059                                                          pEvent->pszFormats,
    1060                                                          ccbFormats,
    1061                                                          &pEvent->cbFormats);
     1285                    rc = vbglR3DnDHGRecvAction(pCtx,
     1286                                               uMsg,
     1287                                               &pEvent->uScreenId,
     1288                                               &pEvent->u.a.uXpos,
     1289                                               &pEvent->u.a.uYpos,
     1290                                               &pEvent->u.a.uDefAction,
     1291                                               &pEvent->u.a.uAllActions,
     1292                                               pEvent->pszFormats,
     1293                                               cbFormatMax,
     1294                                               &pEvent->cbFormats);
    10621295                break;
    10631296            }
    1064             case DragAndDropSvc::HOST_DND_HG_EVT_LEAVE:
    1065             {
    1066                 rc = vbglR3DnDHGProcessLeaveMessage(pCtx);
     1297            case HOST_DND_HG_EVT_LEAVE:
     1298            {
     1299                rc = vbglR3DnDHGRecvLeave(pCtx);
    10671300                break;
    10681301            }
    1069             case DragAndDropSvc::HOST_DND_HG_SND_DATA:
    1070             {
    1071                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
    1072                 if (!pEvent->pszFormats)
    1073                     rc = VERR_NO_MEMORY;
    1074 
    1075                 if (RT_SUCCESS(rc))
    1076                 {
    1077                     pEvent->u.b.pvData = RTMemAlloc(ccbData);
    1078                     if (!pEvent->u.b.pvData)
    1079                     {
    1080                         RTMemFree(pEvent->pszFormats);
    1081                         pEvent->pszFormats = NULL;
    1082 
    1083                         rc = VERR_NO_MEMORY;
    1084                     }
    1085                 }
    1086 
    1087                 if (RT_SUCCESS(rc))
    1088                     rc = vbglR3DnDHGProcessSendDataMessage(pCtx,
    1089                                                            &pEvent->uScreenId,
    1090                                                            pEvent->pszFormats,
    1091                                                            ccbFormats,
    1092                                                            &pEvent->cbFormats,
    1093                                                            &pEvent->u.b.pvData,
    1094                                                            ccbData,
    1095                                                            &pEvent->u.b.cbData);
     1302            case HOST_DND_HG_SND_DATA:
     1303                /* Protocol v1 + v2: Also contains the header data.
     1304                /* Note: Fall through is intentional. */
     1305            case HOST_DND_HG_SND_DATA_HDR:
     1306            {
     1307                rc = vbglR3DnDHGRecvDataMain(pCtx,
     1308                                             /* Screen ID */
     1309                                             &pEvent->uScreenId,
     1310                                             /* Format */
     1311                                             &pEvent->pszFormats,
     1312                                             &pEvent->cbFormats,
     1313                                             /* Data */
     1314                                             &pEvent->u.b.pvData,
     1315                                             &pEvent->u.b.cbData);
    10961316                break;
    10971317            }
    1098             case DragAndDropSvc::HOST_DND_HG_SND_MORE_DATA:
    1099             case DragAndDropSvc::HOST_DND_HG_SND_DIR:
    1100             case DragAndDropSvc::HOST_DND_HG_SND_FILE_DATA:
     1318            case HOST_DND_HG_SND_MORE_DATA:
     1319            case HOST_DND_HG_SND_DIR:
     1320            case HOST_DND_HG_SND_FILE_DATA:
    11011321            {
    11021322                /*
    11031323                 * All messages in this case are handled internally
    1104                  * by vbglR3DnDHGProcessSendDataMessage() and must
    1105                  * be specified by a preceding HOST_DND_HG_SND_DATA call.
     1324                 * by vbglR3DnDHGRecvDataMain() and must be specified
     1325                 * by a preceding HOST_DND_HG_SND_DATA or HOST_DND_HG_SND_DATA_HDR
     1326                 * calls.
    11061327                 */
    11071328                rc = VERR_WRONG_ORDER;
    11081329                break;
    11091330            }
    1110             case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL:
    1111             {
    1112                 rc = vbglR3DnDHGProcessCancelMessage(pCtx);
     1331            case HOST_DND_HG_EVT_CANCEL:
     1332            {
     1333                rc = vbglR3DnDHGRecvCancel(pCtx);
    11131334                break;
    11141335            }
    11151336#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1116             case DragAndDropSvc::HOST_DND_GH_REQ_PENDING:
    1117             {
    1118                 rc = vbglR3DnDGHProcessRequestPendingMessage(pCtx, &pEvent->uScreenId);
     1337            case HOST_DND_GH_REQ_PENDING:
     1338            {
     1339                rc = vbglR3DnDGHRecvPending(pCtx, &pEvent->uScreenId);
    11191340                break;
    11201341            }
    1121             case DragAndDropSvc::HOST_DND_GH_EVT_DROPPED:
    1122             {
    1123                 pEvent->pszFormats = static_cast<char*>(RTMemAlloc(ccbFormats));
     1342            case HOST_DND_GH_EVT_DROPPED:
     1343            {
     1344                pEvent->pszFormats = static_cast<char*>(RTMemAlloc(cbFormatMax));
    11241345                if (!pEvent->pszFormats)
    11251346                    rc = VERR_NO_MEMORY;
    11261347
    11271348                if (RT_SUCCESS(rc))
    1128                     rc = vbglR3DnDGHProcessDroppedMessage(pCtx,
    1129                                                           pEvent->pszFormats,
    1130                                                           ccbFormats,
    1131                                                           &pEvent->cbFormats,
    1132                                                           &pEvent->u.a.uDefAction);
     1349                    rc = vbglR3DnDGHRecvDropped(pCtx,
     1350                                                pEvent->pszFormats,
     1351                                                cbFormatMax,
     1352                                                &pEvent->cbFormats,
     1353                                                &pEvent->u.a.uDefAction);
    11331354                break;
    11341355            }
     
    11451366}
    11461367
    1147 VBGLR3DECL(int) VbglR3DnDHGAcknowledgeOperation(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
     1368VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uAction)
    11481369{
    11491370    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    11501371
    1151     DragAndDropSvc::VBOXDNDHGACKOPMSG Msg;
     1372    VBOXDNDHGACKOPMSG Msg;
    11521373    RT_ZERO(Msg);
    11531374    Msg.hdr.result      = VERR_WRONG_ORDER;
    11541375    Msg.hdr.u32ClientID = pCtx->uClientID;
    1155     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_ACK_OP;
     1376    Msg.hdr.u32Function = GUEST_DND_HG_ACK_OP;
    11561377    Msg.hdr.cParms      = 1;
    11571378
     
    11651386}
    11661387
    1167 VBGLR3DECL(int) VbglR3DnDHGRequestData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
     1388VBGLR3DECL(int) VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char* pcszFormat)
    11681389{
    11691390    AssertPtrReturn(pCtx,       VERR_INVALID_POINTER);
    11701391    AssertPtrReturn(pcszFormat, VERR_INVALID_POINTER);
    11711392
    1172     DragAndDropSvc::VBOXDNDHGREQDATAMSG Msg;
     1393    VBOXDNDHGREQDATAMSG Msg;
    11731394    RT_ZERO(Msg);
    11741395    Msg.hdr.result      = VERR_WRONG_ORDER;
    11751396    Msg.hdr.u32ClientID = pCtx->uClientID;
    1176     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_HG_REQ_DATA;
     1397    Msg.hdr.u32Function = GUEST_DND_HG_REQ_DATA;
    11771398    Msg.hdr.cParms      = 1;
    11781399
    1179     Msg.pFormat.SetPtr((void*)pcszFormat, (uint32_t)strlen(pcszFormat) + 1);
     1400    Msg.pFormat.SetPtr((void*)pcszFormat, strlen(pcszFormat) + 1 /* Include termination */);
    11801401
    11811402    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    11861407}
    11871408
    1188 VBGLR3DECL(int) VbglR3DnDHGSetProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
     1409VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr)
    11891410{
    11901411    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    1191     AssertReturn(uStatus > DragAndDropSvc::DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
    1192 
    1193     DragAndDropSvc::VBOXDNDHGEVTPROGRESSMSG Msg;
     1412    AssertReturn(uStatus > DND_PROGRESS_UNKNOWN, VERR_INVALID_PARAMETER);
     1413
     1414    VBOXDNDHGEVTPROGRESSMSG Msg;
    11941415    RT_ZERO(Msg);
    11951416    Msg.hdr.result      = VERR_WRONG_ORDER;
     
    12101431
    12111432#ifdef VBOX_WITH_DRAG_AND_DROP_GH
    1212 VBGLR3DECL(int) VbglR3DnDGHAcknowledgePending(PVBGLR3GUESTDNDCMDCTX pCtx,
    1213                                               uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats)
     1433VBGLR3DECL(int) VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx,
     1434                                          uint32_t uDefAction, uint32_t uAllActions, const char* pcszFormats, uint32_t cbFormats)
    12141435{
    12151436    AssertPtrReturn(pCtx,        VERR_INVALID_POINTER);
    12161437    AssertPtrReturn(pcszFormats, VERR_INVALID_POINTER);
    1217 
    1218     DragAndDropSvc::VBOXDNDGHACKPENDINGMSG Msg;
     1438    AssertReturn(cbFormats,      VERR_INVALID_PARAMETER);
     1439
     1440    VBOXDNDGHACKPENDINGMSG Msg;
    12191441    RT_ZERO(Msg);
    12201442    Msg.hdr.result      = VERR_WRONG_ORDER;
    12211443    Msg.hdr.u32ClientID = pCtx->uClientID;
    1222     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_ACK_PENDING;
     1444    Msg.hdr.u32Function = GUEST_DND_GH_ACK_PENDING;
    12231445    Msg.hdr.cParms      = 3;
    12241446
    12251447    Msg.uDefAction.SetUInt32(uDefAction);
    12261448    Msg.uAllActions.SetUInt32(uAllActions);
    1227     Msg.pFormat.SetPtr((void*)pcszFormats, (uint32_t)strlen(pcszFormats) + 1);
     1449    Msg.pFormat.SetPtr((void*)pcszFormats, cbFormats);
    12281450
    12291451    int rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     
    12351457
    12361458static int vbglR3DnDGHSendDataInternal(PVBGLR3GUESTDNDCMDCTX pCtx,
    1237                                        void *pvData, uint32_t cbData, uint32_t cbAdditionalData)
     1459                                       void *pvData, uint64_t cbData, PVBOXDNDSNDDATAHDR pDataHdr)
    12381460{
    12391461    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     
    12411463    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
    12421464    /* cbAdditionalData is optional. */
    1243 
    1244     DragAndDropSvc::VBOXDNDGHSENDDATAMSG Msg;
     1465    /* pDataHdr is optional in protocols < v3. */
     1466
     1467    int rc = VINF_SUCCESS;
     1468
     1469    /* For protocol v3 and up we need to send the data header first. */
     1470    if (pCtx->uProtocol > 2)
     1471    {
     1472        AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     1473
     1474        VBOXDNDGHSENDDATAHDRMSG Msg;
     1475        RT_ZERO(Msg);
     1476        Msg.hdr.result      = VERR_WRONG_ORDER;
     1477        Msg.hdr.u32ClientID = pCtx->uClientID;
     1478        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA_HDR;
     1479        Msg.hdr.cParms      = 12;
     1480
     1481        Msg.uContext.SetUInt32(0);                           /** @todo Not used yet. */
     1482        Msg.uFlags.SetUInt32(0);                             /** @todo Not used yet. */
     1483        Msg.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
     1484        Msg.cbTotal.SetUInt64(pDataHdr->cbTotal);
     1485        Msg.cbMeta.SetUInt64(pDataHdr->cbMeta);
     1486        Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     1487        Msg.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
     1488        Msg.cObjects.SetUInt64(pDataHdr->cObjects);
     1489        Msg.enmCompression.SetUInt32(0);                     /** @todo Not used yet. */
     1490        Msg.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
     1491        Msg.pvChecksum.SetPtr(NULL, 0);                      /** @todo Not used yet. */
     1492        Msg.cbChecksum.SetUInt32(0);                         /** @todo Not used yet. */
     1493
     1494        rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1495        if (RT_SUCCESS(rc))
     1496            rc = Msg.hdr.result;
     1497
     1498        LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU64, cObjects=%RU64, rc=%Rrc\n",
     1499                     pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
     1500    }
     1501
     1502    if (RT_SUCCESS(rc))
     1503    {
     1504        VBOXDNDGHSENDDATAMSG Msg;
     1505        RT_ZERO(Msg);
     1506        Msg.hdr.result      = VERR_WRONG_ORDER;
     1507        Msg.hdr.u32ClientID = pCtx->uClientID;
     1508        Msg.hdr.u32Function = GUEST_DND_GH_SND_DATA;
     1509
     1510        if (pCtx->uProtocol > 2)
     1511        {
     1512            Msg.hdr.cParms = 5;
     1513
     1514            Msg.u.v3.uContext.SetUInt32(0);      /** @todo Not used yet. */
     1515            Msg.u.v3.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
     1516            Msg.u.v3.cbChecksum.SetUInt32(0);    /** @todo Not used yet. */
     1517        }
     1518        else
     1519        {
     1520            Msg.hdr.cParms = 2;
     1521
     1522            /* Total amount of bytes to send (meta data + all directory/file objects). */
     1523            /* Note: Only supports uint32_t, so this is *not* a typo. */
     1524            Msg.u.v1.cbTotalBytes.SetUInt32((uint32_t)pDataHdr->cbTotal);
     1525        }
     1526
     1527        uint32_t       cbCurChunk;
     1528        const uint32_t cbMaxChunk = pCtx->cbMaxChunkSize;
     1529        uint32_t       cbSent     = 0;
     1530
     1531        HGCMFunctionParameter *pParm = (pCtx->uProtocol > 2)
     1532                                     ? &Msg.u.v3.pvData
     1533                                     : &Msg.u.v1.pvData;
     1534        while (cbSent < cbData)
     1535        {
     1536            cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     1537            pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
     1538            if (pCtx->uProtocol > 2)
     1539                Msg.u.v3.cbData.SetUInt32(cbCurChunk);
     1540
     1541            rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
     1542            if (RT_SUCCESS(rc))
     1543                rc = Msg.hdr.result;
     1544
     1545            if (RT_FAILURE(rc))
     1546                break;
     1547
     1548            cbSent += cbCurChunk;
     1549        }
     1550
     1551        if (RT_SUCCESS(rc))
     1552            Assert(cbSent == cbData);
     1553    }
     1554
     1555    LogFlowFunc(("Returning rc=%Rrc, cbData=%RU64\n", rc, cbData));
     1556    return rc;
     1557}
     1558
     1559static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
     1560{
     1561    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
     1562    AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
     1563    AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
     1564
     1565    VBOXDNDGHSENDDIRMSG Msg;
    12451566    RT_ZERO(Msg);
    12461567    Msg.hdr.result      = VERR_WRONG_ORDER;
    12471568    Msg.hdr.u32ClientID = pCtx->uClientID;
    1248     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DATA;
    1249     Msg.hdr.cParms      = 2;
    1250 
    1251     /* Total amount of bytes to send (including this data block). */
    1252     Msg.cbTotalBytes.SetUInt32(cbData + cbAdditionalData);
    1253 
    1254     int rc = VINF_SUCCESS;
    1255 
    1256     uint32_t cbCurChunk;
    1257     uint32_t cbMaxChunk = _64K; /** @todo Transfer max. 64K chunks per message. Configurable? */
    1258     uint32_t cbSent     = 0;
    1259 
    1260     while (cbSent < cbData)
    1261     {
    1262         cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
    1263         Msg.pvData.SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
    1264 
    1265         rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_HGCM_CALL(sizeof(Msg)), &Msg, sizeof(Msg));
    1266         if (RT_SUCCESS(rc))
    1267             rc = Msg.hdr.result;
    1268 
    1269         if (RT_FAILURE(rc))
    1270             break;
    1271 
    1272         cbSent += cbCurChunk;
    1273     }
    1274 
    1275     if (RT_SUCCESS(rc))
    1276         Assert(cbSent == cbData);
    1277 
    1278     LogFlowFunc(("Returning rc=%Rrc, cbData=%RU32, cbAddtionalData=%RU32, cbSent=%RU32\n",
    1279                  rc, cbData, cbAdditionalData, cbSent));
    1280     return rc;
    1281 }
    1282 
    1283 static int vbglR3DnDGHSendDir(PVBGLR3GUESTDNDCMDCTX pCtx, DnDURIObject *pObj)
    1284 {
    1285     AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
    1286     AssertPtrReturn(pCtx,                                    VERR_INVALID_POINTER);
    1287     AssertReturn(pObj->GetType() == DnDURIObject::Directory, VERR_INVALID_PARAMETER);
    1288 
    1289     DragAndDropSvc::VBOXDNDGHSENDDIRMSG Msg;
    1290     RT_ZERO(Msg);
    1291     Msg.hdr.result      = VERR_WRONG_ORDER;
    1292     Msg.hdr.u32ClientID = pCtx->uClientID;
    1293     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_DIR;
     1569    Msg.hdr.u32Function = GUEST_DND_GH_SND_DIR;
    12941570    Msg.hdr.cParms      = 3;
    12951571
     
    13321608    if (pCtx->uProtocol >= 2) /* Protocol version 2 and up sends a file header first. */
    13331609    {
    1334         DragAndDropSvc::VBOXDNDGHSENDFILEHDRMSG MsgHdr;
     1610        VBOXDNDGHSENDFILEHDRMSG MsgHdr;
    13351611        RT_ZERO(MsgHdr);
    13361612        MsgHdr.hdr.result      = VERR_WRONG_ORDER;
    13371613        MsgHdr.hdr.u32ClientID = pCtx->uClientID;
    1338         MsgHdr.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_HDR;
     1614        MsgHdr.hdr.u32Function = GUEST_DND_GH_SND_FILE_HDR;
    13391615        MsgHdr.hdr.cParms      = 6;
    13401616
     
    13601636         * Send the actual file data, chunk by chunk.
    13611637         */
    1362         DragAndDropSvc::VBOXDNDGHSENDFILEDATAMSG Msg;
     1638        VBOXDNDGHSENDFILEDATAMSG Msg;
    13631639        RT_ZERO(Msg);
    13641640        Msg.hdr.result      = VERR_WRONG_ORDER;
    13651641        Msg.hdr.u32ClientID = pCtx->uClientID;
    1366         Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_SND_FILE_DATA;
    1367 
    1368         if (pCtx->uProtocol <= 1)
    1369         {
    1370             Msg.hdr.cParms  = 5;
    1371 
    1372             Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
    1373             Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
    1374             Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
    1375         }
    1376         else
    1377         {
    1378             /* Only send context ID, file chunk + chunk size. */
    1379             Msg.hdr.cParms  = 3;
    1380 
    1381             Msg.u.v2.uContext.SetUInt32(0); /** @todo Set context ID. */
     1642        Msg.hdr.u32Function = GUEST_DND_GH_SND_FILE_DATA;
     1643
     1644        switch (pCtx->uProtocol)
     1645        {
     1646            case 3:
     1647            {
     1648                Msg.hdr.cParms = 5;
     1649
     1650                Msg.u.v3.uContext.SetUInt32(0);
     1651                Msg.u.v3.pvChecksum.SetPtr(NULL, 0);
     1652                Msg.u.v3.cbChecksum.SetUInt32(0);
     1653                break;
     1654            }
     1655
     1656            case 2:
     1657            {
     1658                Msg.hdr.cParms  = 3;
     1659
     1660                Msg.u.v2.uContext.SetUInt32(0);
     1661                break;
     1662            }
     1663
     1664            default: /* Protocol v1 */
     1665            {
     1666                Msg.hdr.cParms  = 5;
     1667
     1668                Msg.u.v1.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     1669                Msg.u.v1.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     1670                Msg.u.v1.fMode.SetUInt32(pObj->GetMode());
     1671                break;
     1672            }
    13821673        }
    13831674
     
    13971688                && cbRead)
    13981689            {
    1399                 if (pCtx->uProtocol <= 1)
     1690                switch (pCtx->uProtocol)
    14001691                {
    1401                     Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
    1402                     Msg.u.v1.cbData.SetUInt32(cbRead);
    1403                 }
    1404                 else
    1405                 {
    1406                     Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
    1407                     Msg.u.v2.cbData.SetUInt32(cbRead);
     1692                    case 3:
     1693                    {
     1694                        Msg.u.v3.pvData.SetPtr(pvBuf, cbRead);
     1695                        Msg.u.v3.cbData.SetUInt32(cbRead);
     1696                        /** @todo Calculate + set checksums. */
     1697                        break;
     1698                    }
     1699
     1700                    case 2:
     1701                    {
     1702                        Msg.u.v2.pvData.SetPtr(pvBuf, cbRead);
     1703                        Msg.u.v2.cbData.SetUInt32(cbRead);
     1704                        break;
     1705                    }
     1706
     1707                    default:
     1708                    {
     1709                        Msg.u.v1.pvData.SetPtr(pvBuf, cbRead);
     1710                        Msg.u.v1.cbData.SetUInt32(cbRead);
     1711                        break;
     1712                    }
    14081713                }
    14091714
     
    14591764}
    14601765
    1461 static int vbglR3DnDGHProcessURIMessages(PVBGLR3GUESTDNDCMDCTX pCtx,
    1462                                          const void *pvData, uint32_t cbData)
     1766static int vbglR3DnDGHSendURIData(PVBGLR3GUESTDNDCMDCTX pCtx,
     1767                                  const void *pvData, uint32_t cbData)
    14631768{
    14641769    AssertPtrReturn(pCtx,   VERR_INVALID_POINTER);
     
    14771782    if (RT_SUCCESS(rc))
    14781783    {
    1479         /* Send metadata; in this case it's the (non-recursive) file/directory
    1480          * URI list the host needs to know to initialize the drag'n drop operation. */
     1784        /*
     1785         * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
     1786         * URI list the host needs to know upfront to set up the drag'n drop operation.
     1787         */
    14811788        RTCString strRootDest = lstURI.RootToString();
    1482         Assert(strRootDest.isNotEmpty());
    1483 
    1484         void *pvToSend = (void *)strRootDest.c_str();
    1485         uint32_t cbToSend = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
    1486 
    1487         rc = vbglR3DnDGHSendDataInternal(pCtx, pvToSend, cbToSend,
    1488                                          /* Include total bytes of all file paths,
    1489                                           * file sizes etc. */
    1490                                          (uint32_t)lstURI.TotalBytes());
     1789        if (strRootDest.isNotEmpty())
     1790        {
     1791            void *pvURIList  = (void *)strRootDest.c_str(); /* URI root list. */
     1792            size_t cbURLIist = strRootDest.length() + 1;    /* Include string termination. */
     1793
     1794            /* The total size also contains the size of the meta data. */
     1795            uint64_t cbTotal  = cbURLIist;
     1796                     cbTotal += lstURI.TotalBytes();
     1797
     1798            /* We're going to send an URI list in text format. */
     1799            char szMetaFmt[] = "text/uri-list";
     1800
     1801            VBOXDNDDATAHDR dataHeader;
     1802            dataHeader.uFlags    = 0; /* Flags not used yet. */
     1803            dataHeader.cbTotal   = cbTotal;
     1804            dataHeader.cbMeta    = cbURLIist;
     1805            dataHeader.pvMetaFmt = (void *)szMetaFmt;
     1806            dataHeader.cbMetaFmt = strlen(szMetaFmt) + 1; /* Include termination. */
     1807            dataHeader.cObjects  = lstURI.TotalCount();
     1808
     1809            rc = vbglR3DnDGHSendDataInternal(pCtx,
     1810                                             pvURIList, cbURLIist, &dataHeader);
     1811        }
     1812        else
     1813            rc = VERR_INVALID_PARAMETER;
    14911814    }
    14921815
     
    15201843    if (DnDMIMEHasFileURLs(pszFormat, strlen(pszFormat)))
    15211844    {
    1522         rc = vbglR3DnDGHProcessURIMessages(pCtx, pvData, cbData);
    1523     }
    1524     else
    1525     {
    1526         rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, 0 /* cbAdditionalData */);
     1845        rc = vbglR3DnDGHSendURIData(pCtx, pvData, cbData);
     1846    }
     1847    else /* Send raw data. */
     1848    {
     1849        rc = vbglR3DnDGHSendDataInternal(pCtx, pvData, cbData, NULL /* pDataHdr */);
    15271850    }
    15281851
     
    15411864    AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
    15421865
    1543     DragAndDropSvc::VBOXDNDGHEVTERRORMSG Msg;
     1866    VBOXDNDGHEVTERRORMSG Msg;
    15441867    RT_ZERO(Msg);
    15451868    Msg.hdr.result      = VERR_WRONG_ORDER;
    15461869    Msg.hdr.u32ClientID = pCtx->uClientID;
    1547     Msg.hdr.u32Function = DragAndDropSvc::GUEST_DND_GH_EVT_ERROR;
     1870    Msg.hdr.u32Function = GUEST_DND_GH_EVT_ERROR;
    15481871    Msg.hdr.cParms      = 1;
    15491872
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