VirtualBox

Ignore:
Timestamp:
Apr 26, 2019 6:41:46 AM (6 years ago)
Author:
vboxsync
Message:

Shared Clipboard/URI: First commit; work in progress.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp

    r76553 r78307  
    2929*   Header Files                                                                                                                 *
    3030*********************************************************************************************************************************/
     31#include <VBox/GuestHost/SharedClipboard.h>
     32#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
     33# include <VBox/GuestHost/SharedClipboard-uri.h>
     34#endif
    3135#include <VBox/HostServices/VBoxClipboardSvc.h>
    3236#include <VBox/err.h>
    3337#include <iprt/assert.h>
    3438#include <iprt/string.h>
     39#include <iprt/cpp/ministring.h>
    3540#include "VBoxGuestR3LibInternal.h"
     41
     42
     43/*********************************************************************************************************************************
     44*   Prototypes                                                                                                                   *
     45*********************************************************************************************************************************/
     46#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
     47static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr);
     48static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData);
     49#endif
    3650
    3751
     
    140154
    141155/**
    142  * Advertises guest clipboard formats to the host.
     156 * Writes (advertises) guest clipboard formats to the host.
    143157 *
    144158 * @returns VBox status code.
     
    146160 * @param   fFormats        The formats to advertise.
    147161 */
    148 VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
    149 {
    150     VBoxClipboardFormats Msg;
    151 
    152     VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_FORMATS, 1);
     162VBGLR3DECL(int) VbglR3ClipboardWriteFormats(HGCMCLIENTID idClient, uint32_t fFormats)
     163{
     164    VBoxClipboardWriteFormats Msg;
     165
     166    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FORMATS, 1);
    153167    VbglHGCMParmUInt32Set(&Msg.formats, fFormats);
    154168
     
    156170}
    157171
    158 
    159 /**
    160  * Send guest clipboard data to the host.
     172/**
     173 * Sends guest clipboard data to the host.
    161174 *
    162175 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
     
    169182 * @param   cb              The size of the data.
    170183 */
    171 VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
     184static int vbglR3ClipboardWriteDataRaw(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
    172185{
    173186    VBoxClipboardWriteData Msg;
     
    179192}
    180193
     194/**
     195 * Send guest clipboard data to the host.
     196 *
     197 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
     198 * from the host.
     199 *
     200 * @returns VBox status code.
     201 * @param   idClient        The client id returned by VbglR3ClipboardConnect().
     202 * @param   fFormat         The format of the data.
     203 * @param   pv              The data.
     204 * @param   cb              The size of the data.
     205 */
     206VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
     207{
     208    int rc;
     209#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
     210    if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
     211    {
     212        rc = vbglR3ClipboardSendURIData(idClient, pv, cb);
     213    }
     214    else
     215#else
     216        RT_NOREF(fFormat);
     217#endif
     218        rc = vbglR3ClipboardWriteDataRaw(idClient, fFormat, pv, cb);
     219
     220    if (RT_FAILURE(rc))
     221    {
     222        int rc2 = vbglR3ClipboardSendErrorInternal(idClient, rc);
     223        if (RT_FAILURE(rc2))
     224            LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2));
     225    }
     226
     227    return rc;
     228}
     229
     230#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
     231/**
     232 * Guest -> Host
     233 * Utility function to send clipboard data from guest to the host.
     234 *
     235 * @returns IPRT status code.
     236 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     237 * @param   pvData              Data block to send.
     238 * @param   cbData              Size (in bytes) of data block to send.
     239 * @param   pDataHdr            Data header to use -- needed for accounting.
     240 */
     241static int vbglR3ClipboardSendDataInternal(HGCMCLIENTID idClient,
     242                                           void *pvData, uint64_t cbData, PVBOXCLIPBOARDDATAHDR pDataHdr)
     243{
     244    AssertPtrReturn(pvData,   VERR_INVALID_POINTER);
     245    AssertReturn(cbData,      VERR_INVALID_PARAMETER);
     246    AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
     247
     248    VBoxClipboardWriteDataHdrMsg MsgHdr;
     249    RT_ZERO(MsgHdr);
     250
     251    VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR, 12);
     252    MsgHdr.uContext.SetUInt32(0);                           /** @todo Not used yet. */
     253    MsgHdr.uFlags.SetUInt32(0);                             /** @todo Not used yet. */
     254    MsgHdr.uScreenId.SetUInt32(0);                          /** @todo Not used for guest->host (yet). */
     255    MsgHdr.cbTotal.SetUInt64(pDataHdr->cbTotal);
     256    MsgHdr.cbMeta.SetUInt32(pDataHdr->cbMeta);
     257    MsgHdr.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
     258    MsgHdr.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
     259    MsgHdr.cObjects.SetUInt64(pDataHdr->cObjects);
     260    MsgHdr.enmCompression.SetUInt32(0);                     /** @todo Not used yet. */
     261    MsgHdr.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
     262    MsgHdr.pvChecksum.SetPtr(NULL, 0);                      /** @todo Not used yet. */
     263    MsgHdr.cbChecksum.SetUInt32(0);                         /** @todo Not used yet. */
     264
     265    int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
     266
     267    LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU64, rc=%Rrc\n",
     268                 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
     269
     270    if (RT_SUCCESS(rc))
     271    {
     272        VBoxClipboardWriteDataChunkMsg MsgData;
     273        RT_ZERO(MsgData);
     274
     275        VBGL_HGCM_HDR_INIT(&MsgData.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK, 5);
     276        MsgData.uContext.SetUInt32(0);      /** @todo Not used yet. */
     277        MsgData.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
     278        MsgData.cbChecksum.SetUInt32(0);    /** @todo Not used yet. */
     279
     280        uint32_t       cbCurChunk;
     281        const uint32_t cbMaxChunk = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
     282        uint32_t       cbSent     = 0;
     283
     284        HGCMFunctionParameter *pParm = &MsgData.pvData;
     285
     286        while (cbSent < cbData)
     287        {
     288            cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
     289            pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
     290
     291            MsgData.cbData.SetUInt32(cbCurChunk);
     292
     293            rc = VbglR3HGCMCall(&MsgData.hdr, sizeof(MsgData));
     294            if (RT_FAILURE(rc))
     295                break;
     296
     297            cbSent += cbCurChunk;
     298        }
     299
     300        LogFlowFunc(("cbMaxChunk=%RU32, cbData=%RU64, cbSent=%RU32, rc=%Rrc\n",
     301                     cbMaxChunk, cbData, cbSent, rc));
     302
     303        if (RT_SUCCESS(rc))
     304            Assert(cbSent == cbData);
     305    }
     306
     307    LogFlowFuncLeaveRC(rc);
     308    return rc;
     309}
     310
     311/**
     312 * Guest -> Host
     313 * Utility function to send a guest directory to the host.
     314 *
     315 * @returns IPRT status code.
     316 * @param   idClient        The client id returned by VbglR3ClipboardConnect().
     317 * @param   pObj            URI object containing the directory to send.
     318 */
     319static int vbglR3ClipboardSendDir(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
     320{
     321    AssertPtrReturn(pObj,                                         VERR_INVALID_POINTER);
     322    AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_Directory, VERR_INVALID_PARAMETER);
     323
     324    RTCString strPath = pObj->GetDestPathAbs();
     325    LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
     326                 strPath.c_str(), strPath.length(), pObj->GetMode()));
     327
     328    if (strPath.length() > RTPATH_MAX)
     329        return VERR_INVALID_PARAMETER;
     330
     331    const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */
     332
     333    VBoxClipboardWriteDirMsg Msg;
     334    RT_ZERO(Msg);
     335
     336    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR, 4);
     337    /** @todo Context ID not used yet. */
     338    Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)cbPath);
     339    Msg.cbName.SetUInt32((uint32_t)cbPath);
     340    Msg.fMode.SetUInt32(pObj->GetMode());
     341
     342    return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     343}
     344
     345/**
     346 * Guest -> Host
     347 * Utility function to send a file from the guest to the host.
     348 *
     349 * @returns IPRT status code.
     350 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     351 * @param   pObj                URI object containing the file to send.
     352 */
     353static int vbglR3ClipboardSendFile(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
     354{
     355    AssertPtrReturn(pObj,                                    VERR_INVALID_POINTER);
     356    AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_File, VERR_INVALID_PARAMETER);
     357    AssertReturn(pObj->IsOpen(),                             VERR_INVALID_STATE);
     358
     359    uint32_t cbBuf = _64K;           /** @todo Make this configurable? */
     360    void *pvBuf = RTMemAlloc(cbBuf);
     361    if (!pvBuf)
     362        return VERR_NO_MEMORY;
     363
     364    RTCString strPath = pObj->GetDestPathAbs();
     365
     366    LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
     367                 pObj->GetSize(), pObj->GetMode()));
     368
     369    VBoxClipboardWriteFileHdrMsg MsgHdr;
     370    RT_ZERO(MsgHdr);
     371
     372    VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR, 6);
     373    MsgHdr.uContext.SetUInt32(0);                                                    /* Context ID; unused at the moment. */
     374    MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
     375    MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
     376    MsgHdr.uFlags.SetUInt32(0);                                                      /* Flags; unused at the moment. */
     377    MsgHdr.fMode.SetUInt32(pObj->GetMode());                                         /* File mode */
     378    MsgHdr.cbTotal.SetUInt64(pObj->GetSize());                                       /* File size (in bytes). */
     379
     380    int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
     381
     382    LogFlowFunc(("Sending file header resulted in %Rrc\n", rc));
     383
     384    if (RT_SUCCESS(rc))
     385    {
     386        /*
     387         * Send the actual file data, chunk by chunk.
     388         */
     389        VBoxClipboardWriteFileDataMsg Msg;
     390        RT_ZERO(Msg);
     391
     392        VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA, 5);
     393        Msg.uContext.SetUInt32(0);
     394        Msg.pvChecksum.SetPtr(NULL, 0);
     395        Msg.cbChecksum.SetUInt32(0);
     396
     397        uint64_t cbToReadTotal  = pObj->GetSize();
     398        uint64_t cbWrittenTotal = 0;
     399        while (cbToReadTotal)
     400        {
     401            uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf);
     402            uint32_t cbRead   = 0;
     403            if (cbToRead)
     404                rc = pObj->Read(pvBuf, cbToRead, &cbRead);
     405
     406            LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n",
     407                         cbToReadTotal, cbToRead, cbRead, rc));
     408
     409            if (   RT_SUCCESS(rc)
     410                && cbRead)
     411            {
     412                Msg.pvData.SetPtr(pvBuf, cbRead);
     413                Msg.cbData.SetUInt32(cbRead);
     414                /** @todo Calculate + set checksums. */
     415
     416                rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     417            }
     418
     419            if (RT_FAILURE(rc))
     420            {
     421                LogFlowFunc(("Reading failed with rc=%Rrc\n", rc));
     422                break;
     423            }
     424
     425            Assert(cbRead  <= cbToReadTotal);
     426            cbToReadTotal  -= cbRead;
     427            cbWrittenTotal += cbRead;
     428
     429            LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize()));
     430        };
     431    }
     432
     433    RTMemFree(pvBuf);
     434
     435    LogFlowFuncLeaveRC(rc);
     436    return rc;
     437}
     438
     439/**
     440 * Guest -> Host
     441 * Utility function to send an URI object from guest to the host.
     442 *
     443 * @returns IPRT status code.
     444 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     445 * @param   pObj                URI object to send from guest to the host.
     446 */
     447static int vbglR3ClipboardSendURIObject(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
     448{
     449    AssertPtrReturn(pObj, VERR_INVALID_POINTER);
     450
     451    int rc;
     452
     453    switch (pObj->GetType())
     454    {
     455        case SharedClipboardURIObject::Type_Directory:
     456            rc = vbglR3ClipboardSendDir(idClient, pObj);
     457            break;
     458
     459        case SharedClipboardURIObject::Type_File:
     460            rc = vbglR3ClipboardSendFile(idClient, pObj);
     461            break;
     462
     463        default:
     464            AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType()));
     465            rc = VERR_NOT_IMPLEMENTED;
     466            break;
     467    }
     468
     469    return rc;
     470}
     471
     472/**
     473 * Guest -> Host
     474 * Utility function to send URI data from guest to the host.
     475 *
     476 * @returns IPRT status code.
     477 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     478 * @param   pvData              Block to URI data to send.
     479 * @param   cbData              Size (in bytes) of URI data to send.
     480 */
     481static int vbglR3ClipboardSendURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData)
     482{
     483    AssertPtrReturn(pvData, VERR_INVALID_POINTER);
     484    AssertReturn(cbData,    VERR_INVALID_PARAMETER);
     485
     486    RTCList<RTCString> lstPaths =
     487        RTCString((const char *)pvData, cbData).split("\r\n");
     488
     489    /** @todo Add symlink support (SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */
     490    /** @todo Add lazy loading (SHAREDCLIPBOARDURILIST_FLAGS_LAZY) here. */
     491    uint32_t fFlags = SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN;
     492
     493    SharedClipboardURIList lstURI;
     494    int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags);
     495    if (RT_SUCCESS(rc))
     496    {
     497        /*
     498         * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
     499         * URI list the host needs to know upfront to set up the drag'n drop operation.
     500         */
     501        RTCString strRootDest = lstURI.GetRootEntries();
     502        if (strRootDest.isNotEmpty())
     503        {
     504            void *pvURIList  = (void *)strRootDest.c_str(); /* URI root list. */
     505            uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
     506
     507            /* The total size also contains the size of the meta data. */
     508            uint64_t cbTotal  = cbURLIist;
     509                     cbTotal += lstURI.GetTotalBytes();
     510
     511            /* We're going to send an URI list in text format. */
     512            const char     szMetaFmt[] = "text/uri-list";
     513            const uint32_t cbMetaFmt   = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */
     514
     515            VBOXCLIPBOARDDATAHDR dataHdr;
     516            dataHdr.uFlags    = 0; /* Flags not used yet. */
     517            dataHdr.cbTotal   = cbTotal;
     518            dataHdr.cbMeta    = cbURLIist;
     519            dataHdr.pvMetaFmt = (void *)szMetaFmt;
     520            dataHdr.cbMetaFmt = cbMetaFmt;
     521            dataHdr.cObjects  = lstURI.GetTotalCount();
     522
     523            rc = vbglR3ClipboardSendDataInternal(idClient,
     524                                                 pvURIList, cbURLIist, &dataHdr);
     525        }
     526        else
     527            rc = VERR_INVALID_PARAMETER;
     528    }
     529
     530    if (RT_SUCCESS(rc))
     531    {
     532        while (!lstURI.IsEmpty())
     533        {
     534            SharedClipboardURIObject *pNextObj = lstURI.First();
     535
     536            rc = vbglR3ClipboardSendURIObject(idClient, pNextObj);
     537            if (RT_FAILURE(rc))
     538                break;
     539
     540            lstURI.RemoveFirst();
     541        }
     542    }
     543
     544    return rc;
     545}
     546
     547/**
     548 * Guest -> Host
     549 * Sends an error back to the host.
     550 *
     551 * @returns IPRT status code.
     552 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     553 * @param   rcErr               Error (IPRT-style) to send.
     554 */
     555static int vbglR3ClipboardSendErrorInternal(HGCMCLIENTID idClient, int rcErr)
     556{
     557    VBoxClipboardWriteErrorMsg Msg;
     558    RT_ZERO(Msg);
     559
     560    VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR, 2);
     561    /** @todo Context ID not used yet. */
     562    Msg.uContext.SetUInt32(0);
     563    Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
     564
     565    int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
     566
     567    /*
     568     * Never return an error if the host did not accept the error at the current
     569     * time.  This can be due to the host not having any appropriate callbacks
     570     * set which would handle that error.
     571     *
     572     * bird: Looks like VERR_NOT_SUPPORTED is what the host will return if it
     573     *       doesn't an appropriate callback.  The code used to ignore ALL errors
     574     *       the host would return, also relevant ones.
     575     */
     576    if (RT_FAILURE(rc))
     577        LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
     578    if (rc == VERR_NOT_SUPPORTED)
     579        rc = VINF_SUCCESS;
     580
     581    return rc;
     582}
     583
     584/**
     585 * Guest -> Host
     586 * Send an error back to the host.
     587 *
     588 * @returns IPRT status code.
     589 * @param   idClient            The client id returned by VbglR3ClipboardConnect().
     590 * @param   rcErr               Error (IPRT-style) to send.
     591 */
     592VBGLR3DECL(int) VbglR3ClipboardSendError(HGCMCLIENTID idClient, int rcErr)
     593{
     594    return vbglR3ClipboardSendErrorInternal(idClient, rcErr);
     595}
     596#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
     597
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