VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR3LibClipboard.cpp@ 78897

Last change on this file since 78897 was 78897, checked in by vboxsync, 6 years ago

Shared Clipboard/URI: Update.

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 45.5 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 78897 2019-05-31 15:23:14Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
31#include <VBox/GuestHost/SharedClipboard.h>
32#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
33# include <VBox/GuestHost/SharedClipboard-uri.h>
34#endif
35#include <VBox/HostServices/VBoxClipboardSvc.h>
36#include <VBox/err.h>
37#include <iprt/assert.h>
38#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
39# include <iprt/dir.h>
40# include <iprt/file.h>
41# include <iprt/path.h>
42#endif
43#include <iprt/string.h>
44#include <iprt/cpp/ministring.h>
45
46#include "VBoxGuestR3LibInternal.h"
47
48
49/*********************************************************************************************************************************
50* Prototypes *
51*********************************************************************************************************************************/
52#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
53static int vbglR3ClipboardWriteErrorInternal(HGCMCLIENTID idClient, int rcErr);
54static int vbglR3ClipboardReadURIData(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr);
55static int vbglR3ClipboardWriteURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData);
56#endif
57
58
59/**
60 * Connects to the clipboard service.
61 *
62 * @returns VBox status code
63 * @param pidClient Where to put the client id on success. The client id
64 * must be passed to all the other clipboard calls.
65 */
66VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
67{
68 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
69 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
70 rc = VINF_PERMISSION_DENIED;
71 return rc;
72}
73
74
75/**
76 * Disconnect from the clipboard service.
77 *
78 * @returns VBox status code.
79 * @param idClient The client id returned by VbglR3ClipboardConnect().
80 */
81VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
82{
83 return VbglR3HGCMDisconnect(idClient);
84}
85
86
87/**
88 * Get a host message.
89 *
90 * This will block until a message becomes available.
91 *
92 * @returns VBox status code.
93 * @param idClient The client id returned by VbglR3ClipboardConnect().
94 * @param pidMsg Where to store the message id.
95 * @param pfFormats Where to store the format(s) the message applies to.
96 */
97VBGLR3DECL(int) VbglR3ClipboardGetHostMsg(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
98{
99 VBoxClipboardGetHostMsg Msg;
100
101 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG, 2);
102 VbglHGCMParmUInt32Set(&Msg.msg, 0);
103 VbglHGCMParmUInt32Set(&Msg.formats, 0);
104
105 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
106 if (RT_SUCCESS(rc))
107 {
108 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
109 if (RT_SUCCESS(rc))
110 {
111 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
112 if (RT_SUCCESS(rc2))
113 return rc;
114 }
115 rc = rc2;
116 }
117 *pidMsg = UINT32_MAX - 1;
118 *pfFormats = UINT32_MAX;
119 return rc;
120}
121
122
123/**
124 * Reads data from the host clipboard.
125 *
126 * @returns VBox status code.
127 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
128 *
129 * @param idClient The client id returned by VbglR3ClipboardConnect().
130 * @param fFormat The format we're requesting the data in.
131 * @param pv Where to store the data.
132 * @param cb The size of the buffer pointed to by pv.
133 * @param pcb The actual size of the host clipboard data. May be larger than cb.
134 */
135VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb)
136{
137 VBoxClipboardReadDataMsg Msg;
138
139 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_READ_DATA, 3);
140 VbglHGCMParmUInt32Set(&Msg.format, fFormat);
141 VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);
142 VbglHGCMParmUInt32Set(&Msg.size, 0);
143
144 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
145 if (RT_SUCCESS(rc))
146 {
147 uint32_t cbActual;
148 int rc2 = VbglHGCMParmUInt32Get(&Msg.size, &cbActual);
149 if (RT_SUCCESS(rc2))
150 {
151 *pcb = cbActual;
152 if (cbActual > cb)
153 return VINF_BUFFER_OVERFLOW;
154 return rc;
155 }
156 rc = rc2;
157 }
158 return rc;
159}
160
161#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
162/**
163 * Reads a (meta) data header from the host.
164 *
165 * @returns IPRT status code.
166 * @param idClient The client id returned by VbglR3ClipboardConnect().
167 * @param pDataHdr Where to store the read meta data header.
168 */
169static int vbglR3ClipboardReadDataHdr(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr)
170{
171 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
172
173 VBoxClipboardReadDataHdrMsg Msg;
174 RT_ZERO(Msg);
175 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
176 VBOX_SHARED_CLIPBOARD_FN_READ_DATA_HDR, VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA_HDR);
177 Msg.uContext.SetUInt32(0);
178 Msg.uFlags.SetUInt32(0);
179 Msg.uScreenId.SetUInt32(0);
180 Msg.cbTotal.SetUInt64(0);
181 Msg.cbMeta.SetUInt32(0);
182 Msg.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
183 Msg.cbMetaFmt.SetUInt32(0);
184 Msg.cObjects.SetUInt64(0);
185 Msg.enmCompression.SetUInt32(0);
186 Msg.enmChecksumType.SetUInt32(0);
187 Msg.pvChecksum.SetPtr(pDataHdr->pvChecksum, pDataHdr->cbChecksum);
188 Msg.cbChecksum.SetUInt32(0);
189
190 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
191 if (RT_SUCCESS(rc))
192 {
193 /* Msg.uContext not needed here. */
194 Msg.uFlags.GetUInt32(&pDataHdr->uFlags);
195 Msg.uScreenId.GetUInt32(&pDataHdr->uScreenId);
196 Msg.cbTotal.GetUInt64(&pDataHdr->cbTotal);
197 Msg.cbMeta.GetUInt32(&pDataHdr->cbMeta);
198 Msg.cbMetaFmt.GetUInt32(&pDataHdr->cbMetaFmt);
199 Msg.cObjects.GetUInt64(&pDataHdr->cObjects);
200 Msg.enmCompression.GetUInt32(&pDataHdr->enmCompression);
201 Msg.enmChecksumType.GetUInt32((uint32_t *)&pDataHdr->enmChecksumType);
202 Msg.cbChecksum.GetUInt32(&pDataHdr->cbChecksum);
203 }
204
205 LogFlowFuncLeaveRC(rc);
206 return rc;
207}
208
209/**
210 * Reads a (meta) data chunk from the host.
211 *
212 * @returns IPRT status code.
213 * @param idClient The client id returned by VbglR3ClipboardConnect().
214 * @param pDataHdr Data header to use. Need for accounting and stuff.
215 * @param pvData Where to store the received data from the host.
216 * @param cbData Size (in bytes) of where to store the received data.
217 * @param pcbDataRecv Where to store the received amount of data (in bytes).
218 */
219static int vbglR3ClipboardReadDataChunk(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr,
220 void *pvData, uint32_t cbData, uint32_t *pcbDataRecv)
221{
222 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
223 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
224 AssertReturn(cbData, VERR_INVALID_PARAMETER);
225 AssertPtrNullReturn(pcbDataRecv, VERR_INVALID_POINTER);
226
227 LogFlowFunc(("pvDate=%p, cbData=%RU32\n", pvData, cbData));
228
229 VBoxClipboardReadDataChunkMsg Msg;
230 RT_ZERO(Msg);
231
232 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
233 VBOX_SHARED_CLIPBOARD_FN_READ_DATA_CHUNK, VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA_CHUNK);
234 Msg.pvData.SetPtr(pvData, cbData);
235 Msg.cbData.SetUInt32(0);
236 Msg.pvChecksum.SetPtr(NULL, 0);
237 Msg.cbChecksum.SetUInt32(0);
238
239 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
240 if (RT_SUCCESS(rc))
241 {
242 uint32_t cbDataRecv;
243 rc = Msg.cbData.GetUInt32(&cbDataRecv);
244 AssertRC(rc);
245 if (RT_SUCCESS(rc))
246 {
247 /** @todo Use checksum for validating the received data. */
248 if (pcbDataRecv)
249 *pcbDataRecv = cbDataRecv;
250 LogFlowFuncLeaveRC(rc);
251 return rc;
252 }
253 }
254
255 /* failure */
256 LogFlowFuncLeaveRC(rc);
257 return rc;
258}
259
260/**
261 * Helper function for reading the actual clipboard (meta) data from the host. Do not call directly.
262 *
263 * @returns IPRT status code.
264 * @param idClient The client id returned by VbglR3ClipboardConnect().
265 * @param pDataHdr Where to store the data header data.
266 * @param pMetaData Returns the received meta data. Needs to be free'd by the caller.
267 */
268static int vbglR3ClipboardReadMetaDataLoop(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr,
269 PSHAREDCLIPBOARDMETADATA pMetaData)
270{
271 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
272 AssertPtrReturn(pMetaData, VERR_INVALID_POINTER);
273
274 int rc;
275 uint32_t cbDataRecv;
276
277 LogFlowFuncEnter();
278
279 rc = vbglR3ClipboardReadDataHdr(idClient, pDataHdr);
280 if (RT_FAILURE(rc))
281 return rc;
282
283 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU32\n", pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects));
284 if (pDataHdr->cbMeta)
285 {
286 uint64_t cbDataTmp = 0;
287 void *pvDataTmp = RTMemAlloc(pDataHdr->cbMeta);
288 if (!pvDataTmp)
289 rc = VERR_NO_MEMORY;
290
291 if (RT_SUCCESS(rc))
292 {
293 const uint32_t cbMaxChunkSize = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
294
295 uint8_t *pvDataOff = (uint8_t *)pvDataTmp;
296 while (cbDataTmp < pDataHdr->cbMeta)
297 {
298 rc = vbglR3ClipboardReadDataChunk(idClient, pDataHdr,
299 pvDataOff, RT_MIN(pDataHdr->cbMeta - cbDataTmp, cbMaxChunkSize),
300 &cbDataRecv);
301 if (RT_SUCCESS(rc))
302 {
303 LogFlowFunc(("cbDataRecv=%RU32, cbDataTmp=%RU64\n", cbDataRecv, cbDataTmp));
304 Assert(cbDataTmp + cbDataRecv <= pDataHdr->cbMeta);
305 cbDataTmp += cbDataRecv;
306 pvDataOff += cbDataRecv;
307 }
308 else
309 break;
310 }
311
312 if (RT_SUCCESS(rc))
313 {
314 Assert(cbDataTmp == pDataHdr->cbMeta);
315
316 LogFlowFunc(("Received %RU64 bytes of data\n", cbDataTmp));
317
318 pMetaData->pvMeta = pvDataTmp;
319 pMetaData->cbMeta = cbDataTmp;
320 pMetaData->cbUsed = cbDataTmp;
321 }
322 else
323 RTMemFree(pvDataTmp);
324 }
325 }
326 else
327 SharedClipboardMetaDataDestroy(pMetaData);
328
329 LogFlowFuncLeaveRC(rc);
330 return rc;
331}
332
333/**
334 * Reads the actual meta data from the host, extended version.
335 *
336 * @returns IPRT status code.
337 * @param idClient The client id returned by VbglR3ClipboardConnect().
338 * @param URIList Where to store received meta data.
339 */
340static int vbglR3ClipboardReadMetaDataEx(HGCMCLIENTID idClient, SharedClipboardURIList &URIList)
341{
342 /* The rest is optional. */
343
344 VBOXCLIPBOARDDATAHDR dataHdr;
345 RT_ZERO(dataHdr);
346
347 dataHdr.cbMetaFmt = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
348 dataHdr.pvMetaFmt = RTMemAlloc(dataHdr.cbMetaFmt);
349 if (!dataHdr.pvMetaFmt)
350 return VERR_NO_MEMORY;
351
352 SHAREDCLIPBOARDMETADATA dataMeta;
353 SharedClipboardMetaDataInit(&dataMeta);
354
355 int rc = vbglR3ClipboardReadMetaDataLoop(idClient, &dataHdr, &dataMeta);
356 if (RT_SUCCESS(rc))
357 {
358 /**
359 * Check if this is an URI event. If so, let VbglR3 do all the actual
360 * data transfer + file/directory creation internally without letting
361 * the caller know.
362 *
363 * This keeps the actual (guest OS-)dependent client (like VBoxClient /
364 * VBoxTray) small by not having too much redundant code.
365 */
366 Assert(dataHdr.cbMetaFmt);
367 AssertPtr(dataHdr.pvMetaFmt);
368 if (SharedClipboardMIMEHasFileURLs((char *)dataHdr.pvMetaFmt, dataHdr.cbMetaFmt)) /* URI data. */
369 {
370 rc = URIList.SetFromURIData(dataMeta.pvMeta, dataMeta.cbMeta, 0 /* fFlags */);
371
372 #if 0
373 if (RT_SUCCESS(rc))
374 rc = vbglR3ClipboardReadURIData(idClient, &dataHdr);
375
376 if (RT_SUCCESS(rc))
377 {
378 if (pvData)
379 {
380 /* Reuse data buffer to fill in the transformed URI file list. */
381 RTMemFree(pvData);
382 pvData = NULL;
383 }
384
385 #if 0
386 RTCString strData = lstURI.GetRootEntries(clipboardCache.GetDirAbs());
387 Assert(!strData.isEmpty());
388
389 cbData = strData.length() + 1;
390 LogFlowFunc(("URI list has %zu bytes\n", cbData));
391
392 pvData = RTMemAlloc(cbData);
393 if (pvData)
394 {
395 memcpy(pvData, strData.c_str(), cbData);
396 }
397 else
398 rc = VERR_NO_MEMORY;
399 #endif
400 }
401 #endif
402 }
403 else /* Raw data. */
404 {
405 /** @todo Implement this. */
406 }
407
408 SharedClipboardMetaDataDestroy(&dataMeta);
409 }
410
411 if (dataHdr.pvMetaFmt)
412 {
413 RTMemFree(dataHdr.pvMetaFmt);
414 dataHdr.pvMetaFmt = NULL;
415 }
416
417 LogFlowFuncLeaveRC(rc);
418 return rc;
419}
420
421/**
422 * Reads the actual meta data from the host.
423 *
424 * @returns IPRT status code.
425 * @param idClient The client id returned by VbglR3ClipboardConnect().
426 * @param URIList Where to store received meta data.
427 */
428VBGLR3DECL(int) VbglR3ClipboardReadMetaData(HGCMCLIENTID idClient, SharedClipboardURIList &URIList)
429{
430 return vbglR3ClipboardReadMetaDataEx(idClient, URIList);
431}
432
433VBGLR3DECL(int) VbglR3ClipboardWriteMetaData(HGCMCLIENTID idClient, const SharedClipboardURIList &URIList)
434{
435 RT_NOREF(idClient, URIList);
436 return 0;
437}
438
439/**
440 * Utility function to read a directory entry from the host.
441 *
442 * @returns IPRT status code.
443 * @param idClient The client id returned by VbglR3ClipboardConnect().
444 * @param pszDirname Where to store the directory name of the directory being created.
445 * @param cbDirname Size (in bytes) of where to store the directory name of the directory being created.
446 * @param pcbDirnameRecv Size (in bytes) of the actual directory name received.
447 * @param pfMode Where to store the directory creation mode.
448 */
449static int vbglR3ClipboardReadDir(HGCMCLIENTID idClient,
450 char *pszDirname,
451 uint32_t cbDirname,
452 uint32_t *pcbDirnameRecv,
453 uint32_t *pfMode)
454{
455 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER);
456 AssertReturn(cbDirname, VERR_INVALID_PARAMETER);
457 AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
458 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
459
460 VBoxClipboardReadDirMsg Msg;
461 RT_ZERO(Msg);
462
463 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_READ_DIR, VBOX_SHARED_CLIPBOARD_CPARMS_READ_DIR);
464 /** @todo Context ID not used yet. */
465 Msg.uContext.SetUInt32(0);
466 Msg.pvName.SetPtr(pszDirname, cbDirname);
467 Msg.cbName.SetUInt32(cbDirname);
468 Msg.fMode.SetUInt32(0);
469
470 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
471 if (RT_SUCCESS(rc))
472 {
473 /** @todo Context ID not used yet. */
474 rc = Msg.cbName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
475 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
476
477 AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
478 }
479
480 return rc;
481}
482
483/**
484 * Utility function to receive a file header from the host.
485 *
486 * @returns IPRT status code.
487 * @param idClient The client id returned by VbglR3ClipboardConnect().
488 * @param pszFilename Where to store the file name of the file being transferred.
489 * @param cbFilename Size (in bytes) of where to store the file name of the file being transferred.
490 * @param puFlags File transfer flags. Currently not being used.
491 * @param pfMode Where to store the file creation mode.
492 * @param pcbTotal Where to store the file size (in bytes).
493 */
494static int vbglR3ClipboardReadFileHdr(HGCMCLIENTID idClient,
495 char *pszFilename,
496 uint32_t cbFilename,
497 uint32_t *puFlags,
498 uint32_t *pfMode,
499 uint64_t *pcbTotal)
500{
501 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
502 AssertReturn(cbFilename, VERR_INVALID_PARAMETER);
503 AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
504 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
505 AssertReturn(pcbTotal, VERR_INVALID_POINTER);
506
507 VBoxClipboardReadFileHdrMsg Msg;
508 RT_ZERO(Msg);
509
510 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
511 VBOX_SHARED_CLIPBOARD_FN_READ_FILE_HDR, VBOX_SHARED_CLIPBOARD_CPARMS_READ_FILE_HDR);
512 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
513 Msg.pvName.SetPtr(pszFilename, cbFilename);
514 Msg.cbName.SetUInt32(cbFilename);
515 Msg.uFlags.SetUInt32(0);
516 Msg.fMode.SetUInt32(0);
517 Msg.cbTotal.SetUInt64(0);
518
519 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
520 if (RT_SUCCESS(rc))
521 {
522 /** @todo Get context ID. */
523 rc = Msg.uFlags.GetUInt32(puFlags); AssertRC(rc);
524 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
525 rc = Msg.cbTotal.GetUInt64(pcbTotal); AssertRC(rc);
526 }
527
528 return rc;
529}
530
531/**
532 * Utility function to receive a file data chunk from the host.
533 *
534 * @returns IPRT status code.
535 * @param idClient The client id returned by VbglR3ClipboardConnect().
536 * @param pvData Where to store the file data chunk.
537 * @param cbData Size (in bytes) of where to store the data chunk.
538 * @param pcbDataRecv Size (in bytes) of the actual data chunk size received.
539 */
540static int vbglR3ClipboardReadFileData(HGCMCLIENTID idClient,
541 void *pvData,
542 uint32_t cbData,
543 uint32_t *pcbDataRecv)
544{
545 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
546 AssertReturn(cbData, VERR_INVALID_PARAMETER);
547 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
548
549 VBoxClipboardReadFileDataMsg Msg;
550 RT_ZERO(Msg);
551
552 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
553 VBOX_SHARED_CLIPBOARD_FN_READ_FILE_DATA, VBOX_SHARED_CLIPBOARD_CPARMS_READ_FILE_DATA);
554 Msg.uContext.SetUInt32(0);
555 Msg.pvData.SetPtr(pvData, cbData);
556 Msg.cbData.SetUInt32(0);
557 Msg.pvChecksum.SetPtr(NULL, 0);
558 Msg.cbChecksum.SetUInt32(0);
559
560 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
561 if (RT_SUCCESS(rc))
562 {
563 /** @todo Context ID not used yet. */
564 rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
565 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
566 /** @todo Add checksum support. */
567 }
568
569 return rc;
570}
571
572/**
573 * Helper function for receiving URI data from the host. Do not call directly.
574 * This function also will take care of the file creation / locking on the guest.
575 *
576 * @returns IPRT status code.
577 * @param idClient The client id returned by VbglR3ClipboardConnect().
578 * @param pDataHdr Data header to use. Needed for accounting.
579 */
580static int vbglR3ClipboardReadURIData(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr)
581{
582 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
583
584 RT_NOREF(idClient, pDataHdr);
585
586#if 0
587
588 /* Only count the raw data minus the already received meta data. */
589 Assert(pDataHdr->cbTotal >= pDataHdr->cbMeta);
590 uint64_t cbToRecvBytes = pDataHdr->cbTotal - pDataHdr->cbMeta;
591 uint64_t cToRecvObjs = pDataHdr->cObjects;
592
593 LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64, (cbTotal=%RU64, cbMeta=%RU32)\n",
594 cbToRecvBytes, cToRecvObjs, pDataHdr->cbTotal, pDataHdr->cbMeta));
595
596 /* Anything to do at all? */
597 /* Note: Do not check for cbToRecvBytes == 0 here, as this might be just
598 * a bunch of 0-byte files to be transferred. */
599 if (!cToRecvObjs)
600 return VINF_SUCCESS;
601
602 /*
603 * Allocate temporary chunk buffer.
604 */
605 uint32_t cbChunkMax = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
606 void *pvChunk = RTMemAlloc(cbChunkMax);
607 if (!pvChunk)
608 return VERR_NO_MEMORY;
609 uint32_t cbChunkRead = 0;
610
611 uint64_t cbFileSize = 0; /* Total file size (in bytes). */
612 uint64_t cbFileWritten = 0; /* Written bytes. */
613
614 char *pszDropDir = NULL;
615
616 int rc;
617
618 /*
619 * Enter the main loop of retieving files + directories.
620 */
621 SharedClipboardURIObject objFile(SharedClipboardURIObject::Type_File);
622
623 char szPathName[RTPATH_MAX] = { 0 };
624 uint32_t cbPathName = 0;
625 uint32_t fFlags = 0;
626 uint32_t fMode = 0;
627
628 do
629 {
630 LogFlowFunc(("Wating for new message ...\n"));
631
632 uint32_t uNextMsg;
633 uint32_t cNextParms;
634 rc = vbglR3DnDGetNextMsgType(idClient, &uNextMsg, &cNextParms, true /* fWait */);
635 if (RT_SUCCESS(rc))
636 {
637 LogFlowFunc(("uNextMsg=%RU32, cNextParms=%RU32\n", uNextMsg, cNextParms));
638
639 switch (uNextMsg)
640 {
641 case HOST_DND_HG_SND_DIR:
642 {
643 rc = vbglR3ClipboardReadDir(idClient,
644 szPathName,
645 sizeof(szPathName),
646 &cbPathName,
647 &fMode);
648 LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
649 szPathName, cbPathName, fMode, rc));
650
651 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
652 if (pszPathAbs)
653 {
654#ifdef RT_OS_WINDOWS
655 uint32_t fCreationMode = (fMode & RTFS_DOS_MASK) | RTFS_DOS_NT_NORMAL;
656#else
657 uint32_t fCreationMode = (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU;
658#endif
659 rc = RTDirCreate(pszPathAbs, fCreationMode, 0);
660 /*if (RT_SUCCESS(rc))
661 rc = pDroppedFiles->AddDir(pszPathAbs);*/
662
663 if (RT_SUCCESS(rc))
664 {
665 Assert(cToRecvObjs);
666 cToRecvObjs--;
667 }
668
669 RTStrFree(pszPathAbs);
670 }
671 else
672 rc = VERR_NO_MEMORY;
673 break;
674 }
675 case HOST_DND_HG_SND_FILE_HDR:
676 case HOST_DND_HG_SND_FILE_DATA:
677 {
678 if (uNextMsg == HOST_DND_HG_SND_FILE_HDR)
679 {
680 rc = vbglR3ClipboardReadFileHdr(idClient,
681 szPathName,
682 sizeof(szPathName),
683 &fFlags,
684 &fMode,
685 &cbFileSize);
686 LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR: "
687 "szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
688 szPathName, fFlags, fMode, cbFileSize, rc));
689 }
690 else
691 {
692 rc = vbglR3ClipboardReadFileData(idClient,
693 pvChunk,
694 cbChunkMax,
695 &cbChunkRead);
696 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: "
697 "cbChunkRead=%RU32, rc=%Rrc\n", cbChunkRead, rc));
698 }
699
700 if ( RT_SUCCESS(rc)
701 && uNextMsg == HOST_DND_HG_SND_FILE_HDR)
702 {
703 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
704 if (pszPathAbs)
705 {
706 LogFlowFunc(("Opening pszPathName=%s, cbPathName=%RU32, fMode=0x%x, cbFileSize=%zu\n",
707 szPathName, cbPathName, fMode, cbFileSize));
708
709 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE
710 | RTFILE_O_CREATE_REPLACE;
711
712 /* Is there already a file open, e.g. in transfer? */
713 if (!objFile.IsOpen())
714 {
715 RTCString strPathAbs(pszPathAbs);
716#ifdef RT_OS_WINDOWS
717 uint32_t fCreationMode = (fMode & RTFS_DOS_MASK) | RTFS_DOS_NT_NORMAL;
718#else
719 uint32_t fCreationMode = (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR;
720#endif
721 rc = objFile.OpenEx(strPathAbs, SharedClipboardURIObject::View_Target, fOpen, fCreationMode);
722 if (RT_SUCCESS(rc))
723 {
724 //rc = pDroppedFiles->AddFile(strPathAbs.c_str());
725 if (RT_SUCCESS(rc))
726 {
727 cbFileWritten = 0;
728 objFile.SetSize(cbFileSize);
729 }
730 }
731 }
732 else
733 {
734 AssertMsgFailed(("ObjType=%RU32\n", objFile.GetType()));
735 rc = VERR_WRONG_ORDER;
736 }
737
738 RTStrFree(pszPathAbs);
739 }
740 else
741 rc = VERR_NO_MEMORY;
742 }
743
744 if ( RT_SUCCESS(rc)
745 && uNextMsg == HOST_DND_HG_SND_FILE_DATA
746 && cbChunkRead)
747 {
748 uint32_t cbChunkWritten;
749 rc = objFile.Write(pvChunk, cbChunkRead, &cbChunkWritten);
750 if (RT_SUCCESS(rc))
751 {
752 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
753 "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n",
754 cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize));
755
756 cbFileWritten += cbChunkWritten;
757
758 Assert(cbChunkRead <= cbToRecvBytes);
759 cbToRecvBytes -= cbChunkRead;
760 }
761 }
762
763 /* Data transfer complete? Close the file. */
764 bool fClose = objFile.IsComplete();
765 if (fClose)
766 {
767 Assert(cToRecvObjs);
768 cToRecvObjs--;
769 }
770
771 /* Only since protocol v2 we know the file size upfront. */
772 Assert(cbFileWritten <= cbFileSize);
773
774 if (fClose)
775 {
776 LogFlowFunc(("Closing file\n"));
777 objFile.Close();
778 }
779
780 break;
781 }
782 default:
783 {
784 LogFlowFunc(("Message %RU32 not supported\n", uNextMsg));
785 rc = VERR_NOT_SUPPORTED;
786 break;
787 }
788 }
789 }
790
791 if (RT_FAILURE(rc))
792 break;
793
794 LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64\n", cbToRecvBytes, cToRecvObjs));
795 if ( !cbToRecvBytes
796 && !cToRecvObjs)
797 {
798 break;
799 }
800
801 } while (RT_SUCCESS(rc));
802
803 LogFlowFunc(("Loop ended with %Rrc\n", rc));
804
805 /* All URI data processed? */
806 if (rc == VERR_NO_DATA)
807 rc = VINF_SUCCESS;
808
809 /* Delete temp buffer again. */
810 if (pvChunk)
811 RTMemFree(pvChunk);
812
813 /* Cleanup on failure or if the user has canceled the operation or
814 * something else went wrong. */
815 if (RT_FAILURE(rc))
816 {
817 objFile.Close();
818 }
819 else
820 {
821 /** @todo Compare the URI list with the dirs/files we really transferred. */
822 /** @todo Implement checksum verification, if any. */
823 }
824
825 LogFlowFuncLeaveRC(rc);
826 return rc;
827#endif
828 return 0;
829}
830#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
831
832/**
833 * Reports (advertises) guest clipboard formats to the host.
834 *
835 * @returns VBox status code.
836 * @param idClient The client id returned by VbglR3ClipboardConnect().
837 * @param fFormats The formats to advertise.
838 */
839VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
840{
841 VBoxClipboardWriteFormatsMsg Msg;
842
843 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_REPORT_FORMATS, 1);
844 VbglHGCMParmUInt32Set(&Msg.formats, fFormats);
845
846 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
847}
848
849/**
850 * Sends guest clipboard data to the host.
851 *
852 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
853 * from the host.
854 *
855 * @returns VBox status code.
856 * @param idClient The client id returned by VbglR3ClipboardConnect().
857 * @param fFormat The format of the data.
858 * @param pv The data.
859 * @param cb The size of the data.
860 */
861static int vbglR3ClipboardWriteDataRaw(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
862{
863 VBoxClipboardWriteDataMsg Msg;
864 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA, 2);
865 VbglHGCMParmUInt32Set(&Msg.format, fFormat);
866 VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);
867
868 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
869}
870
871/**
872 * Send guest clipboard data to the host.
873 *
874 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
875 * from the host.
876 *
877 * @returns VBox status code.
878 * @param idClient The client id returned by VbglR3ClipboardConnect().
879 * @param fFormat The format of the data.
880 * @param pv The data.
881 * @param cb The size of the data.
882 */
883VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
884{
885 int rc;
886#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
887 if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
888 {
889 rc = vbglR3ClipboardWriteURIData(idClient, pv, cb);
890 }
891 else
892#else
893 RT_NOREF(fFormat);
894#endif
895 rc = vbglR3ClipboardWriteDataRaw(idClient, fFormat, pv, cb);
896
897#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
898 if (RT_FAILURE(rc))
899 {
900 int rc2 = vbglR3ClipboardWriteErrorInternal(idClient, rc);
901 if (RT_FAILURE(rc2))
902 LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2));
903 }
904#endif
905
906 return rc;
907}
908
909#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
910/**
911 * Utility function to write clipboard data from guest to the host.
912 *
913 * @returns IPRT status code.
914 * @param idClient The client id returned by VbglR3ClipboardConnect().
915 * @param pvData Data block to send.
916 * @param cbData Size (in bytes) of data block to send.
917 * @param pDataHdr Data header to use -- needed for accounting.
918 */
919static int vbglR3ClipboardWriteDataInternal(HGCMCLIENTID idClient,
920 void *pvData, uint64_t cbData, PVBOXCLIPBOARDDATAHDR pDataHdr)
921{
922 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
923 AssertReturn(cbData, VERR_INVALID_PARAMETER);
924 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
925
926 VBoxClipboardWriteDataHdrMsg MsgHdr;
927 RT_ZERO(MsgHdr);
928
929 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR, 12);
930 MsgHdr.uContext.SetUInt32(0); /** @todo Not used yet. */
931 MsgHdr.uFlags.SetUInt32(0); /** @todo Not used yet. */
932 MsgHdr.uScreenId.SetUInt32(0); /** @todo Not used for guest->host (yet). */
933 MsgHdr.cbTotal.SetUInt64(pDataHdr->cbTotal);
934 MsgHdr.cbMeta.SetUInt32(pDataHdr->cbMeta);
935 MsgHdr.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
936 MsgHdr.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
937 MsgHdr.cObjects.SetUInt64(pDataHdr->cObjects);
938 MsgHdr.enmCompression.SetUInt32(0); /** @todo Not used yet. */
939 MsgHdr.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
940 MsgHdr.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
941 MsgHdr.cbChecksum.SetUInt32(0); /** @todo Not used yet. */
942
943 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
944
945 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU64, rc=%Rrc\n",
946 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
947
948 if (RT_SUCCESS(rc))
949 {
950 VBoxClipboardWriteDataChunkMsg MsgData;
951 RT_ZERO(MsgData);
952
953 VBGL_HGCM_HDR_INIT(&MsgData.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK, 5);
954 MsgData.uContext.SetUInt32(0); /** @todo Not used yet. */
955 MsgData.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
956 MsgData.cbChecksum.SetUInt32(0); /** @todo Not used yet. */
957
958 uint32_t cbCurChunk;
959 const uint32_t cbMaxChunk = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
960 uint32_t cbSent = 0;
961
962 HGCMFunctionParameter *pParm = &MsgData.pvData;
963
964 while (cbSent < cbData)
965 {
966 cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
967 pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
968
969 MsgData.cbData.SetUInt32(cbCurChunk);
970
971 rc = VbglR3HGCMCall(&MsgData.hdr, sizeof(MsgData));
972 if (RT_FAILURE(rc))
973 break;
974
975 cbSent += cbCurChunk;
976 }
977
978 LogFlowFunc(("cbMaxChunk=%RU32, cbData=%RU64, cbSent=%RU32, rc=%Rrc\n",
979 cbMaxChunk, cbData, cbSent, rc));
980
981 if (RT_SUCCESS(rc))
982 Assert(cbSent == cbData);
983 }
984
985 LogFlowFuncLeaveRC(rc);
986 return rc;
987}
988
989/**
990 * Utility function to write a guest directory to the host.
991 *
992 * @returns IPRT status code.
993 * @param idClient The client id returned by VbglR3ClipboardConnect().
994 * @param pObj URI object containing the directory to send.
995 */
996static int vbglR3ClipboardWriteDir(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
997{
998 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
999 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_Directory, VERR_INVALID_PARAMETER);
1000
1001 RTCString strPath = pObj->GetDestPathAbs();
1002 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
1003 strPath.c_str(), strPath.length(), pObj->GetMode()));
1004
1005 if (strPath.length() > RTPATH_MAX)
1006 return VERR_INVALID_PARAMETER;
1007
1008 const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */
1009
1010 VBoxClipboardWriteDirMsg Msg;
1011 RT_ZERO(Msg);
1012
1013 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR, 4);
1014 /** @todo Context ID not used yet. */
1015 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)cbPath);
1016 Msg.cbName.SetUInt32((uint32_t)cbPath);
1017 Msg.fMode.SetUInt32(pObj->GetMode());
1018
1019 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1020}
1021
1022/**
1023 * Utility function to write a file from the guest to the host.
1024 *
1025 * @returns IPRT status code.
1026 * @param idClient The client id returned by VbglR3ClipboardConnect().
1027 * @param pObj URI object containing the file to send.
1028 */
1029static int vbglR3ClipboardWriteFile(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
1030{
1031 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
1032 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_File, VERR_INVALID_PARAMETER);
1033 AssertReturn(pObj->IsOpen(), VERR_INVALID_STATE);
1034
1035 uint32_t cbBuf = _64K; /** @todo Make this configurable? */
1036 void *pvBuf = RTMemAlloc(cbBuf);
1037 if (!pvBuf)
1038 return VERR_NO_MEMORY;
1039
1040 RTCString strPath = pObj->GetDestPathAbs();
1041
1042 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
1043 pObj->GetSize(), pObj->GetMode()));
1044
1045 VBoxClipboardWriteFileHdrMsg MsgHdr;
1046 RT_ZERO(MsgHdr);
1047
1048 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR, 6);
1049 MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */
1050 MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
1051 MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
1052 MsgHdr.uFlags.SetUInt32(0); /* Flags; unused at the moment. */
1053 MsgHdr.fMode.SetUInt32(pObj->GetMode()); /* File mode */
1054 MsgHdr.cbTotal.SetUInt64(pObj->GetSize()); /* File size (in bytes). */
1055
1056 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
1057
1058 LogFlowFunc(("Sending file header resulted in %Rrc\n", rc));
1059
1060 if (RT_SUCCESS(rc))
1061 {
1062 /*
1063 * Send the actual file data, chunk by chunk.
1064 */
1065 VBoxClipboardWriteFileDataMsg Msg;
1066 RT_ZERO(Msg);
1067
1068 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA, 5);
1069 Msg.uContext.SetUInt32(0);
1070 Msg.pvChecksum.SetPtr(NULL, 0);
1071 Msg.cbChecksum.SetUInt32(0);
1072
1073 uint64_t cbToReadTotal = pObj->GetSize();
1074 uint64_t cbWrittenTotal = 0;
1075 while (cbToReadTotal)
1076 {
1077 uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf);
1078 uint32_t cbRead = 0;
1079 if (cbToRead)
1080 rc = pObj->Read(pvBuf, cbToRead, &cbRead);
1081
1082 LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n",
1083 cbToReadTotal, cbToRead, cbRead, rc));
1084
1085 if ( RT_SUCCESS(rc)
1086 && cbRead)
1087 {
1088 Msg.pvData.SetPtr(pvBuf, cbRead);
1089 Msg.cbData.SetUInt32(cbRead);
1090 /** @todo Calculate + set checksums. */
1091
1092 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1093 }
1094
1095 if (RT_FAILURE(rc))
1096 {
1097 LogFlowFunc(("Reading failed with rc=%Rrc\n", rc));
1098 break;
1099 }
1100
1101 Assert(cbRead <= cbToReadTotal);
1102 cbToReadTotal -= cbRead;
1103 cbWrittenTotal += cbRead;
1104
1105 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize()));
1106 };
1107 }
1108
1109 RTMemFree(pvBuf);
1110
1111 LogFlowFuncLeaveRC(rc);
1112 return rc;
1113}
1114
1115/**
1116 * Utility function to write an URI object from guest to the host.
1117 *
1118 * @returns IPRT status code.
1119 * @param idClient The client id returned by VbglR3ClipboardConnect().
1120 * @param pObj URI object to send from guest to the host.
1121 */
1122static int vbglR3ClipboardWriteURIObject(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
1123{
1124 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
1125
1126 int rc;
1127
1128 switch (pObj->GetType())
1129 {
1130 case SharedClipboardURIObject::Type_Directory:
1131 rc = vbglR3ClipboardWriteDir(idClient, pObj);
1132 break;
1133
1134 case SharedClipboardURIObject::Type_File:
1135 rc = vbglR3ClipboardWriteFile(idClient, pObj);
1136 break;
1137
1138 default:
1139 AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType()));
1140 rc = VERR_NOT_IMPLEMENTED;
1141 break;
1142 }
1143
1144 return rc;
1145}
1146
1147/**
1148 * Utility function to write URI data from guest to the host.
1149 *
1150 * @returns IPRT status code.
1151 * @param idClient The client id returned by VbglR3ClipboardConnect().
1152 * @param pvData Block to URI data to send.
1153 * @param cbData Size (in bytes) of URI data to send.
1154 */
1155static int vbglR3ClipboardWriteURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData)
1156{
1157 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1158 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1159
1160 RTCList<RTCString> lstPaths =
1161 RTCString((const char *)pvData, cbData).split("\r\n");
1162
1163 /** @todo Add symlink support (SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */
1164 /** @todo Add lazy loading (SHAREDCLIPBOARDURILIST_FLAGS_LAZY) here. */
1165 uint32_t fFlags = SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN;
1166
1167 SharedClipboardURIList lstURI;
1168 int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags);
1169 if (RT_SUCCESS(rc))
1170 {
1171 /*
1172 * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
1173 * URI list the host needs to know upfront to set up the Shared Clipboard operation.
1174 */
1175 RTCString strRootDest = lstURI.GetRootEntries();
1176 if (strRootDest.isNotEmpty())
1177 {
1178 void *pvURIList = (void *)strRootDest.c_str(); /* URI root list. */
1179 uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
1180
1181 /* The total size also contains the size of the meta data. */
1182 uint64_t cbTotal = cbURLIist;
1183 cbTotal += lstURI.GetTotalBytes();
1184
1185 /* We're going to send an URI list in text format. */
1186 const char szMetaFmt[] = "text/uri-list";
1187 const uint32_t cbMetaFmt = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */
1188
1189 VBOXCLIPBOARDDATAHDR dataHdr;
1190 dataHdr.uFlags = 0; /* Flags not used yet. */
1191 dataHdr.cbTotal = cbTotal;
1192 dataHdr.cbMeta = cbURLIist;
1193 dataHdr.pvMetaFmt = (void *)szMetaFmt;
1194 dataHdr.cbMetaFmt = cbMetaFmt;
1195 dataHdr.cObjects = lstURI.GetTotalCount();
1196
1197 rc = vbglR3ClipboardWriteDataInternal(idClient,
1198 pvURIList, cbURLIist, &dataHdr);
1199 }
1200 else
1201 rc = VERR_INVALID_PARAMETER;
1202 }
1203
1204 if (RT_SUCCESS(rc))
1205 {
1206 while (!lstURI.IsEmpty())
1207 {
1208 SharedClipboardURIObject *pNextObj = lstURI.First();
1209
1210 rc = vbglR3ClipboardWriteURIObject(idClient, pNextObj);
1211 if (RT_FAILURE(rc))
1212 break;
1213
1214 lstURI.RemoveFirst();
1215 }
1216 }
1217
1218 return rc;
1219}
1220
1221/**
1222 * Writes an error to the host.
1223 *
1224 * @returns IPRT status code.
1225 * @param idClient The client id returned by VbglR3ClipboardConnect().
1226 * @param rcErr Error (IPRT-style) to send.
1227 */
1228static int vbglR3ClipboardWriteErrorInternal(HGCMCLIENTID idClient, int rcErr)
1229{
1230 VBoxClipboardWriteErrorMsg Msg;
1231 RT_ZERO(Msg);
1232
1233 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR, 2);
1234 /** @todo Context ID not used yet. */
1235 Msg.uContext.SetUInt32(0);
1236 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
1237
1238 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1239
1240 /*
1241 * Never return an error if the host did not accept the error at the current
1242 * time. This can be due to the host not having any appropriate callbacks
1243 * set which would handle that error.
1244 *
1245 * bird: Looks like VERR_NOT_SUPPORTED is what the host will return if it
1246 * doesn't an appropriate callback. The code used to ignore ALL errors
1247 * the host would return, also relevant ones.
1248 */
1249 if (RT_FAILURE(rc))
1250 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
1251 if (rc == VERR_NOT_SUPPORTED)
1252 rc = VINF_SUCCESS;
1253
1254 return rc;
1255}
1256
1257/**
1258 * Writes an error back to the host.
1259 *
1260 * @returns IPRT status code.
1261 * @param idClient The client id returned by VbglR3ClipboardConnect().
1262 * @param rcErr Error (IPRT-style) to send.
1263 */
1264VBGLR3DECL(int) vbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
1265{
1266 return vbglR3ClipboardWriteErrorInternal(idClient, rcErr);
1267}
1268#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
1269
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette