VirtualBox

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

Last change on this file since 78725 was 78725, 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: 46.7 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 78725 2019-05-24 13:15:59Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, 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 ppvData Returns the received meta data. Needs to be free'd by the caller.
267 * @param pcbData Where to store the size (in bytes) of the received meta data.
268 */
269static int vbglR3ClipboardReadMetaDataLoop(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr,
270 void **ppvData, uint64_t *pcbData)
271{
272 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
273 AssertPtrReturn(ppvData, VERR_INVALID_POINTER);
274 AssertPtrReturn(pcbData, VERR_INVALID_POINTER);
275
276 int rc;
277 uint32_t cbDataRecv;
278
279 LogFlowFuncEnter();
280
281 rc = vbglR3ClipboardReadDataHdr(idClient, pDataHdr);
282 if (RT_FAILURE(rc))
283 return rc;
284
285 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU32\n", pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects));
286 if (pDataHdr->cbMeta)
287 {
288 uint64_t cbDataTmp = 0;
289 void *pvDataTmp = RTMemAlloc(pDataHdr->cbMeta);
290 if (!pvDataTmp)
291 rc = VERR_NO_MEMORY;
292
293 if (RT_SUCCESS(rc))
294 {
295 const uint32_t cbMaxChunkSize = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
296
297 uint8_t *pvDataOff = (uint8_t *)pvDataTmp;
298 while (cbDataTmp < pDataHdr->cbMeta)
299 {
300 rc = vbglR3ClipboardReadDataChunk(idClient, pDataHdr,
301 pvDataOff, RT_MIN(pDataHdr->cbMeta - cbDataTmp, cbMaxChunkSize),
302 &cbDataRecv);
303 if (RT_SUCCESS(rc))
304 {
305 LogFlowFunc(("cbDataRecv=%RU32, cbDataTmp=%RU64\n", cbDataRecv, cbDataTmp));
306 Assert(cbDataTmp + cbDataRecv <= pDataHdr->cbMeta);
307 cbDataTmp += cbDataRecv;
308 pvDataOff += cbDataRecv;
309 }
310 else
311 break;
312 }
313
314 if (RT_SUCCESS(rc))
315 {
316 Assert(cbDataTmp == pDataHdr->cbMeta);
317
318 LogFlowFunc(("Received %RU64 bytes of data\n", cbDataTmp));
319
320 *ppvData = pvDataTmp;
321 *pcbData = cbDataTmp;
322 }
323 else
324 RTMemFree(pvDataTmp);
325 }
326 }
327 else
328 {
329 *ppvData = NULL;
330 *pcbData = 0;
331 }
332
333 LogFlowFuncLeaveRC(rc);
334 return rc;
335}
336
337/**
338 * Main function for reading the actual meta data from the host, extended version.
339 *
340 * @returns IPRT status code.
341 * @param idClient The client id returned by VbglR3ClipboardConnect().
342 * @param pEnmType Where to store the meta data type. Optional.
343 * @param ppvData Returns the received meta data. Needs to be free'd by the caller. Optional.
344 * @param pcbData Where to store the size (in bytes) of the received meta data. Optional.
345 */
346static int vbglR3ClipboardReadMetaDataMainEx(HGCMCLIENTID idClient,
347 VBGLR3GUESTDNDMETADATATYPE *pEnmType,
348 void **ppvData,
349 uint32_t *pcbData)
350{
351 /* The rest is optional. */
352
353 VBOXCLIPBOARDDATAHDR dataHdr;
354 RT_ZERO(dataHdr);
355
356 dataHdr.cbMetaFmt = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
357 dataHdr.pvMetaFmt = RTMemAlloc(dataHdr.cbMetaFmt);
358 if (!dataHdr.pvMetaFmt)
359 return VERR_NO_MEMORY;
360
361 SharedClipboardURIList lstURI;
362
363 void *pvData = NULL;
364 uint64_t cbData = 0;
365
366 int rc = vbglR3ClipboardReadMetaDataLoop(idClient, &dataHdr, &pvData, &cbData);
367 if (RT_SUCCESS(rc))
368 {
369 /**
370 * Check if this is an URI event. If so, let VbglR3 do all the actual
371 * data transfer + file/directory creation internally without letting
372 * the caller know.
373 *
374 * This keeps the actual (guest OS-)dependent client (like VBoxClient /
375 * VBoxTray) small by not having too much redundant code.
376 */
377 Assert(dataHdr.cbMetaFmt);
378 AssertPtr(dataHdr.pvMetaFmt);
379 if (SharedClipboardMIMEHasFileURLs((char *)dataHdr.pvMetaFmt, dataHdr.cbMetaFmt)) /* URI data. */
380 {
381 AssertPtr(pvData);
382 Assert(cbData);
383
384 rc = lstURI.SetFromURIData(pvData, cbData, 0 /* fFlags */);
385 if (RT_SUCCESS(rc))
386 rc = vbglR3ClipboardReadURIData(idClient, &dataHdr);
387
388 if (RT_SUCCESS(rc)) /** @todo Remove this block as soon as we hand in DnDURIList. */
389 {
390 if (pvData)
391 {
392 /* Reuse data buffer to fill in the transformed URI file list. */
393 RTMemFree(pvData);
394 pvData = NULL;
395 }
396
397 #if 0
398 RTCString strData = lstURI.GetRootEntries(clipboardCache.GetDirAbs());
399 Assert(!strData.isEmpty());
400
401 cbData = strData.length() + 1;
402 LogFlowFunc(("URI list has %zu bytes\n", cbData));
403
404 pvData = RTMemAlloc(cbData);
405 if (pvData)
406 {
407 memcpy(pvData, strData.c_str(), cbData);
408
409 if (pEnmType)
410 *pEnmType = VBGLR3GUESTDNDMETADATATYPE_URI_LIST;
411 }
412 else
413 rc = VERR_NO_MEMORY;
414 #endif
415 }
416 }
417 else /* Raw data. */
418 {
419 if (pEnmType)
420 *pEnmType = VBGLR3GUESTDNDMETADATATYPE_RAW;
421 }
422 }
423
424 if (dataHdr.pvMetaFmt)
425 RTMemFree(dataHdr.pvMetaFmt);
426
427 if (RT_SUCCESS(rc))
428 {
429 if ( pvData
430 && cbData)
431 {
432 if (pcbData)
433 *pcbData = cbData;
434 if (ppvData)
435 *ppvData = pvData;
436 else
437 RTMemFree(pvData);
438 }
439 }
440 else if ( RT_FAILURE(rc)
441 && rc != VERR_CANCELLED)
442 {
443 if (pvData)
444 RTMemFree(pvData);
445 }
446
447 LogFlowFuncLeaveRC(rc);
448 return rc;
449}
450
451/**
452 * Main function for reading the actual meta data from the host.
453 *
454 * @returns IPRT status code.
455 * @param idClient The client id returned by VbglR3ClipboardConnect().
456 * @param pMeta Where to store the actual meta data received from the host.
457 */
458static int vbglR3ClipboardReadMetaDataMain(HGCMCLIENTID idClient, PVBGLR3GUESTDNDMETADATA pMeta)
459{
460 AssertPtrReturn(pMeta, VERR_INVALID_POINTER);
461
462 int rc = vbglR3ClipboardReadMetaDataMainEx(idClient,
463 &pMeta->enmType,
464 &pMeta->pvMeta,
465 &pMeta->cbMeta);
466 return rc;
467}
468
469/**
470 * Utility function to read a directory entry from the host.
471 *
472 * @returns IPRT status code.
473 * @param idClient The client id returned by VbglR3ClipboardConnect().
474 * @param pszDirname Where to store the directory name of the directory being created.
475 * @param cbDirname Size (in bytes) of where to store the directory name of the directory being created.
476 * @param pcbDirnameRecv Size (in bytes) of the actual directory name received.
477 * @param pfMode Where to store the directory creation mode.
478 */
479static int vbglR3ClipboardReadDir(HGCMCLIENTID idClient,
480 char *pszDirname,
481 uint32_t cbDirname,
482 uint32_t *pcbDirnameRecv,
483 uint32_t *pfMode)
484{
485 AssertPtrReturn(pszDirname, VERR_INVALID_POINTER);
486 AssertReturn(cbDirname, VERR_INVALID_PARAMETER);
487 AssertPtrReturn(pcbDirnameRecv, VERR_INVALID_POINTER);
488 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
489
490 VBoxClipboardReadDirMsg Msg;
491 RT_ZERO(Msg);
492
493 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_READ_DIR, VBOX_SHARED_CLIPBOARD_CPARMS_READ_DIR);
494 /** @todo Context ID not used yet. */
495 Msg.uContext.SetUInt32(0);
496 Msg.pvName.SetPtr(pszDirname, cbDirname);
497 Msg.cbName.SetUInt32(cbDirname);
498 Msg.fMode.SetUInt32(0);
499
500 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
501 if (RT_SUCCESS(rc))
502 {
503 /** @todo Context ID not used yet. */
504 rc = Msg.cbName.GetUInt32(pcbDirnameRecv); AssertRC(rc);
505 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
506
507 AssertReturn(cbDirname >= *pcbDirnameRecv, VERR_TOO_MUCH_DATA);
508 }
509
510 return rc;
511}
512
513/**
514 * Utility function to receive a file header from the host.
515 *
516 * @returns IPRT status code.
517 * @param idClient The client id returned by VbglR3ClipboardConnect().
518 * @param pszFilename Where to store the file name of the file being transferred.
519 * @param cbFilename Size (in bytes) of where to store the file name of the file being transferred.
520 * @param puFlags File transfer flags. Currently not being used.
521 * @param pfMode Where to store the file creation mode.
522 * @param pcbTotal Where to store the file size (in bytes).
523 */
524static int vbglR3ClipboardReadFileHdr(HGCMCLIENTID idClient,
525 char *pszFilename,
526 uint32_t cbFilename,
527 uint32_t *puFlags,
528 uint32_t *pfMode,
529 uint64_t *pcbTotal)
530{
531 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
532 AssertReturn(cbFilename, VERR_INVALID_PARAMETER);
533 AssertPtrReturn(puFlags, VERR_INVALID_POINTER);
534 AssertPtrReturn(pfMode, VERR_INVALID_POINTER);
535 AssertReturn(pcbTotal, VERR_INVALID_POINTER);
536
537 VBoxClipboardReadFileHdrMsg Msg;
538 RT_ZERO(Msg);
539
540 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
541 VBOX_SHARED_CLIPBOARD_FN_READ_FILE_HDR, VBOX_SHARED_CLIPBOARD_CPARMS_READ_FILE_HDR);
542 Msg.uContext.SetUInt32(0); /** @todo Not used yet. */
543 Msg.pvName.SetPtr(pszFilename, cbFilename);
544 Msg.cbName.SetUInt32(cbFilename);
545 Msg.uFlags.SetUInt32(0);
546 Msg.fMode.SetUInt32(0);
547 Msg.cbTotal.SetUInt64(0);
548
549 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
550 if (RT_SUCCESS(rc))
551 {
552 /** @todo Get context ID. */
553 rc = Msg.uFlags.GetUInt32(puFlags); AssertRC(rc);
554 rc = Msg.fMode.GetUInt32(pfMode); AssertRC(rc);
555 rc = Msg.cbTotal.GetUInt64(pcbTotal); AssertRC(rc);
556 }
557
558 return rc;
559}
560
561/**
562 * Utility function to receive a file data chunk from the host.
563 *
564 * @returns IPRT status code.
565 * @param idClient The client id returned by VbglR3ClipboardConnect().
566 * @param pvData Where to store the file data chunk.
567 * @param cbData Size (in bytes) of where to store the data chunk.
568 * @param pcbDataRecv Size (in bytes) of the actual data chunk size received.
569 */
570static int vbglR3ClipboardReadFileData(HGCMCLIENTID idClient,
571 void *pvData,
572 uint32_t cbData,
573 uint32_t *pcbDataRecv)
574{
575 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
576 AssertReturn(cbData, VERR_INVALID_PARAMETER);
577 AssertPtrReturn(pcbDataRecv, VERR_INVALID_POINTER);
578
579 VBoxClipboardReadFileDataMsg Msg;
580 RT_ZERO(Msg);
581
582 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient,
583 VBOX_SHARED_CLIPBOARD_FN_READ_FILE_DATA, VBOX_SHARED_CLIPBOARD_CPARMS_READ_FILE_DATA);
584 Msg.uContext.SetUInt32(0);
585 Msg.pvData.SetPtr(pvData, cbData);
586 Msg.cbData.SetUInt32(0);
587 Msg.pvChecksum.SetPtr(NULL, 0);
588 Msg.cbChecksum.SetUInt32(0);
589
590 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
591 if (RT_SUCCESS(rc))
592 {
593 /** @todo Context ID not used yet. */
594 rc = Msg.cbData.GetUInt32(pcbDataRecv); AssertRC(rc);
595 AssertReturn(cbData >= *pcbDataRecv, VERR_TOO_MUCH_DATA);
596 /** @todo Add checksum support. */
597 }
598
599 return rc;
600}
601
602/**
603 * Helper function for receiving URI data from the host. Do not call directly.
604 * This function also will take care of the file creation / locking on the guest.
605 *
606 * @returns IPRT status code.
607 * @param idClient The client id returned by VbglR3ClipboardConnect().
608 * @param pDataHdr Data header to use. Needed for accounting.
609 */
610static int vbglR3ClipboardReadURIData(HGCMCLIENTID idClient, PVBOXCLIPBOARDDATAHDR pDataHdr)
611{
612 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
613
614 RT_NOREF(idClient, pDataHdr);
615
616#if 0
617
618 /* Only count the raw data minus the already received meta data. */
619 Assert(pDataHdr->cbTotal >= pDataHdr->cbMeta);
620 uint64_t cbToRecvBytes = pDataHdr->cbTotal - pDataHdr->cbMeta;
621 uint64_t cToRecvObjs = pDataHdr->cObjects;
622
623 LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64, (cbTotal=%RU64, cbMeta=%RU32)\n",
624 cbToRecvBytes, cToRecvObjs, pDataHdr->cbTotal, pDataHdr->cbMeta));
625
626 /* Anything to do at all? */
627 /* Note: Do not check for cbToRecvBytes == 0 here, as this might be just
628 * a bunch of 0-byte files to be transferred. */
629 if (!cToRecvObjs)
630 return VINF_SUCCESS;
631
632 /*
633 * Allocate temporary chunk buffer.
634 */
635 uint32_t cbChunkMax = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
636 void *pvChunk = RTMemAlloc(cbChunkMax);
637 if (!pvChunk)
638 return VERR_NO_MEMORY;
639 uint32_t cbChunkRead = 0;
640
641 uint64_t cbFileSize = 0; /* Total file size (in bytes). */
642 uint64_t cbFileWritten = 0; /* Written bytes. */
643
644 char *pszDropDir = NULL;
645
646 int rc;
647
648 /*
649 * Enter the main loop of retieving files + directories.
650 */
651 SharedClipboardURIObject objFile(SharedClipboardURIObject::Type_File);
652
653 char szPathName[RTPATH_MAX] = { 0 };
654 uint32_t cbPathName = 0;
655 uint32_t fFlags = 0;
656 uint32_t fMode = 0;
657
658 do
659 {
660 LogFlowFunc(("Wating for new message ...\n"));
661
662 uint32_t uNextMsg;
663 uint32_t cNextParms;
664 rc = vbglR3DnDGetNextMsgType(idClient, &uNextMsg, &cNextParms, true /* fWait */);
665 if (RT_SUCCESS(rc))
666 {
667 LogFlowFunc(("uNextMsg=%RU32, cNextParms=%RU32\n", uNextMsg, cNextParms));
668
669 switch (uNextMsg)
670 {
671 case HOST_DND_HG_SND_DIR:
672 {
673 rc = vbglR3ClipboardReadDir(idClient,
674 szPathName,
675 sizeof(szPathName),
676 &cbPathName,
677 &fMode);
678 LogFlowFunc(("HOST_DND_HG_SND_DIR pszPathName=%s, cbPathName=%RU32, fMode=0x%x, rc=%Rrc\n",
679 szPathName, cbPathName, fMode, rc));
680
681 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
682 if (pszPathAbs)
683 {
684#ifdef RT_OS_WINDOWS
685 uint32_t fCreationMode = (fMode & RTFS_DOS_MASK) | RTFS_DOS_NT_NORMAL;
686#else
687 uint32_t fCreationMode = (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU;
688#endif
689 rc = RTDirCreate(pszPathAbs, fCreationMode, 0);
690 /*if (RT_SUCCESS(rc))
691 rc = pDroppedFiles->AddDir(pszPathAbs);*/
692
693 if (RT_SUCCESS(rc))
694 {
695 Assert(cToRecvObjs);
696 cToRecvObjs--;
697 }
698
699 RTStrFree(pszPathAbs);
700 }
701 else
702 rc = VERR_NO_MEMORY;
703 break;
704 }
705 case HOST_DND_HG_SND_FILE_HDR:
706 case HOST_DND_HG_SND_FILE_DATA:
707 {
708 if (uNextMsg == HOST_DND_HG_SND_FILE_HDR)
709 {
710 rc = vbglR3ClipboardReadFileHdr(idClient,
711 szPathName,
712 sizeof(szPathName),
713 &fFlags,
714 &fMode,
715 &cbFileSize);
716 LogFlowFunc(("HOST_DND_HG_SND_FILE_HDR: "
717 "szPathName=%s, fFlags=0x%x, fMode=0x%x, cbFileSize=%RU64, rc=%Rrc\n",
718 szPathName, fFlags, fMode, cbFileSize, rc));
719 }
720 else
721 {
722 rc = vbglR3ClipboardReadFileData(idClient,
723 pvChunk,
724 cbChunkMax,
725 &cbChunkRead);
726 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA: "
727 "cbChunkRead=%RU32, rc=%Rrc\n", cbChunkRead, rc));
728 }
729
730 if ( RT_SUCCESS(rc)
731 && uNextMsg == HOST_DND_HG_SND_FILE_HDR)
732 {
733 char *pszPathAbs = RTPathJoinA(pszDropDir, szPathName);
734 if (pszPathAbs)
735 {
736 LogFlowFunc(("Opening pszPathName=%s, cbPathName=%RU32, fMode=0x%x, cbFileSize=%zu\n",
737 szPathName, cbPathName, fMode, cbFileSize));
738
739 uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE
740 | RTFILE_O_CREATE_REPLACE;
741
742 /* Is there already a file open, e.g. in transfer? */
743 if (!objFile.IsOpen())
744 {
745 RTCString strPathAbs(pszPathAbs);
746#ifdef RT_OS_WINDOWS
747 uint32_t fCreationMode = (fMode & RTFS_DOS_MASK) | RTFS_DOS_NT_NORMAL;
748#else
749 uint32_t fCreationMode = (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR;
750#endif
751 rc = objFile.OpenEx(strPathAbs, SharedClipboardURIObject::View_Target, fOpen, fCreationMode);
752 if (RT_SUCCESS(rc))
753 {
754 //rc = pDroppedFiles->AddFile(strPathAbs.c_str());
755 if (RT_SUCCESS(rc))
756 {
757 cbFileWritten = 0;
758 objFile.SetSize(cbFileSize);
759 }
760 }
761 }
762 else
763 {
764 AssertMsgFailed(("ObjType=%RU32\n", objFile.GetType()));
765 rc = VERR_WRONG_ORDER;
766 }
767
768 RTStrFree(pszPathAbs);
769 }
770 else
771 rc = VERR_NO_MEMORY;
772 }
773
774 if ( RT_SUCCESS(rc)
775 && uNextMsg == HOST_DND_HG_SND_FILE_DATA
776 && cbChunkRead)
777 {
778 uint32_t cbChunkWritten;
779 rc = objFile.Write(pvChunk, cbChunkRead, &cbChunkWritten);
780 if (RT_SUCCESS(rc))
781 {
782 LogFlowFunc(("HOST_DND_HG_SND_FILE_DATA "
783 "cbChunkRead=%RU32, cbChunkWritten=%RU32, cbFileWritten=%RU64 cbFileSize=%RU64\n",
784 cbChunkRead, cbChunkWritten, cbFileWritten + cbChunkWritten, cbFileSize));
785
786 cbFileWritten += cbChunkWritten;
787
788 Assert(cbChunkRead <= cbToRecvBytes);
789 cbToRecvBytes -= cbChunkRead;
790 }
791 }
792
793 /* Data transfer complete? Close the file. */
794 bool fClose = objFile.IsComplete();
795 if (fClose)
796 {
797 Assert(cToRecvObjs);
798 cToRecvObjs--;
799 }
800
801 /* Only since protocol v2 we know the file size upfront. */
802 Assert(cbFileWritten <= cbFileSize);
803
804 if (fClose)
805 {
806 LogFlowFunc(("Closing file\n"));
807 objFile.Close();
808 }
809
810 break;
811 }
812 default:
813 {
814 LogFlowFunc(("Message %RU32 not supported\n", uNextMsg));
815 rc = VERR_NOT_SUPPORTED;
816 break;
817 }
818 }
819 }
820
821 if (RT_FAILURE(rc))
822 break;
823
824 LogFlowFunc(("cbToRecvBytes=%RU64, cToRecvObjs=%RU64\n", cbToRecvBytes, cToRecvObjs));
825 if ( !cbToRecvBytes
826 && !cToRecvObjs)
827 {
828 break;
829 }
830
831 } while (RT_SUCCESS(rc));
832
833 LogFlowFunc(("Loop ended with %Rrc\n", rc));
834
835 /* All URI data processed? */
836 if (rc == VERR_NO_DATA)
837 rc = VINF_SUCCESS;
838
839 /* Delete temp buffer again. */
840 if (pvChunk)
841 RTMemFree(pvChunk);
842
843 /* Cleanup on failure or if the user has canceled the operation or
844 * something else went wrong. */
845 if (RT_FAILURE(rc))
846 {
847 objFile.Close();
848 }
849 else
850 {
851 /** @todo Compare the URI list with the dirs/files we really transferred. */
852 /** @todo Implement checksum verification, if any. */
853 }
854
855 LogFlowFuncLeaveRC(rc);
856 return rc;
857#endif
858 return 0;
859}
860#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
861
862/**
863 * Reports (advertises) guest clipboard formats to the host.
864 *
865 * @returns VBox status code.
866 * @param idClient The client id returned by VbglR3ClipboardConnect().
867 * @param fFormats The formats to advertise.
868 */
869VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
870{
871 VBoxClipboardWriteFormatsMsg Msg;
872
873 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_REPORT_FORMATS, 1);
874 VbglHGCMParmUInt32Set(&Msg.formats, fFormats);
875
876 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
877}
878
879/**
880 * Sends guest clipboard data to the host.
881 *
882 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
883 * from the host.
884 *
885 * @returns VBox status code.
886 * @param idClient The client id returned by VbglR3ClipboardConnect().
887 * @param fFormat The format of the data.
888 * @param pv The data.
889 * @param cb The size of the data.
890 */
891static int vbglR3ClipboardWriteDataRaw(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
892{
893 VBoxClipboardWriteDataMsg Msg;
894 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA, 2);
895 VbglHGCMParmUInt32Set(&Msg.format, fFormat);
896 VbglHGCMParmPtrSet(&Msg.ptr, pv, cb);
897
898 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
899}
900
901/**
902 * Send guest clipboard data to the host.
903 *
904 * This is usually called in reply to a VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA message
905 * from the host.
906 *
907 * @returns VBox status code.
908 * @param idClient The client id returned by VbglR3ClipboardConnect().
909 * @param fFormat The format of the data.
910 * @param pv The data.
911 * @param cb The size of the data.
912 */
913VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
914{
915 int rc;
916#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
917 if (fFormat == VBOX_SHARED_CLIPBOARD_FMT_URI_LIST)
918 {
919 rc = vbglR3ClipboardWriteURIData(idClient, pv, cb);
920 }
921 else
922#else
923 RT_NOREF(fFormat);
924#endif
925 rc = vbglR3ClipboardWriteDataRaw(idClient, fFormat, pv, cb);
926
927#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
928 if (RT_FAILURE(rc))
929 {
930 int rc2 = vbglR3ClipboardWriteErrorInternal(idClient, rc);
931 if (RT_FAILURE(rc2))
932 LogFlowFunc(("Unable to send error (%Rrc) to host, rc=%Rrc\n", rc, rc2));
933 }
934#endif
935
936 return rc;
937}
938
939#ifdef VBOX_WITH_SHARED_CLIPBOARD_URI_LIST
940/**
941 * Utility function to write clipboard data from guest to the host.
942 *
943 * @returns IPRT status code.
944 * @param idClient The client id returned by VbglR3ClipboardConnect().
945 * @param pvData Data block to send.
946 * @param cbData Size (in bytes) of data block to send.
947 * @param pDataHdr Data header to use -- needed for accounting.
948 */
949static int vbglR3ClipboardWriteDataInternal(HGCMCLIENTID idClient,
950 void *pvData, uint64_t cbData, PVBOXCLIPBOARDDATAHDR pDataHdr)
951{
952 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
953 AssertReturn(cbData, VERR_INVALID_PARAMETER);
954 AssertPtrReturn(pDataHdr, VERR_INVALID_POINTER);
955
956 VBoxClipboardWriteDataHdrMsg MsgHdr;
957 RT_ZERO(MsgHdr);
958
959 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_HDR, 12);
960 MsgHdr.uContext.SetUInt32(0); /** @todo Not used yet. */
961 MsgHdr.uFlags.SetUInt32(0); /** @todo Not used yet. */
962 MsgHdr.uScreenId.SetUInt32(0); /** @todo Not used for guest->host (yet). */
963 MsgHdr.cbTotal.SetUInt64(pDataHdr->cbTotal);
964 MsgHdr.cbMeta.SetUInt32(pDataHdr->cbMeta);
965 MsgHdr.pvMetaFmt.SetPtr(pDataHdr->pvMetaFmt, pDataHdr->cbMetaFmt);
966 MsgHdr.cbMetaFmt.SetUInt32(pDataHdr->cbMetaFmt);
967 MsgHdr.cObjects.SetUInt64(pDataHdr->cObjects);
968 MsgHdr.enmCompression.SetUInt32(0); /** @todo Not used yet. */
969 MsgHdr.enmChecksumType.SetUInt32(RTDIGESTTYPE_INVALID); /** @todo Not used yet. */
970 MsgHdr.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
971 MsgHdr.cbChecksum.SetUInt32(0); /** @todo Not used yet. */
972
973 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
974
975 LogFlowFunc(("cbTotal=%RU64, cbMeta=%RU32, cObjects=%RU64, rc=%Rrc\n",
976 pDataHdr->cbTotal, pDataHdr->cbMeta, pDataHdr->cObjects, rc));
977
978 if (RT_SUCCESS(rc))
979 {
980 VBoxClipboardWriteDataChunkMsg MsgData;
981 RT_ZERO(MsgData);
982
983 VBGL_HGCM_HDR_INIT(&MsgData.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA_CHUNK, 5);
984 MsgData.uContext.SetUInt32(0); /** @todo Not used yet. */
985 MsgData.pvChecksum.SetPtr(NULL, 0); /** @todo Not used yet. */
986 MsgData.cbChecksum.SetUInt32(0); /** @todo Not used yet. */
987
988 uint32_t cbCurChunk;
989 const uint32_t cbMaxChunk = VBOX_SHARED_CLIPBOARD_MAX_CHUNK_SIZE;
990 uint32_t cbSent = 0;
991
992 HGCMFunctionParameter *pParm = &MsgData.pvData;
993
994 while (cbSent < cbData)
995 {
996 cbCurChunk = RT_MIN(cbData - cbSent, cbMaxChunk);
997 pParm->SetPtr(static_cast<uint8_t *>(pvData) + cbSent, cbCurChunk);
998
999 MsgData.cbData.SetUInt32(cbCurChunk);
1000
1001 rc = VbglR3HGCMCall(&MsgData.hdr, sizeof(MsgData));
1002 if (RT_FAILURE(rc))
1003 break;
1004
1005 cbSent += cbCurChunk;
1006 }
1007
1008 LogFlowFunc(("cbMaxChunk=%RU32, cbData=%RU64, cbSent=%RU32, rc=%Rrc\n",
1009 cbMaxChunk, cbData, cbSent, rc));
1010
1011 if (RT_SUCCESS(rc))
1012 Assert(cbSent == cbData);
1013 }
1014
1015 LogFlowFuncLeaveRC(rc);
1016 return rc;
1017}
1018
1019/**
1020 * Utility function to write a guest directory to the host.
1021 *
1022 * @returns IPRT status code.
1023 * @param idClient The client id returned by VbglR3ClipboardConnect().
1024 * @param pObj URI object containing the directory to send.
1025 */
1026static int vbglR3ClipboardWriteDir(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
1027{
1028 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
1029 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_Directory, VERR_INVALID_PARAMETER);
1030
1031 RTCString strPath = pObj->GetDestPathAbs();
1032 LogFlowFunc(("strDir=%s (%zu), fMode=0x%x\n",
1033 strPath.c_str(), strPath.length(), pObj->GetMode()));
1034
1035 if (strPath.length() > RTPATH_MAX)
1036 return VERR_INVALID_PARAMETER;
1037
1038 const uint32_t cbPath = (uint32_t)strPath.length() + 1; /* Include termination. */
1039
1040 VBoxClipboardWriteDirMsg Msg;
1041 RT_ZERO(Msg);
1042
1043 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_DIR, 4);
1044 /** @todo Context ID not used yet. */
1045 Msg.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)cbPath);
1046 Msg.cbName.SetUInt32((uint32_t)cbPath);
1047 Msg.fMode.SetUInt32(pObj->GetMode());
1048
1049 return VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1050}
1051
1052/**
1053 * Utility function to write a file from the guest to the host.
1054 *
1055 * @returns IPRT status code.
1056 * @param idClient The client id returned by VbglR3ClipboardConnect().
1057 * @param pObj URI object containing the file to send.
1058 */
1059static int vbglR3ClipboardWriteFile(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
1060{
1061 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
1062 AssertReturn(pObj->GetType() == SharedClipboardURIObject::Type_File, VERR_INVALID_PARAMETER);
1063 AssertReturn(pObj->IsOpen(), VERR_INVALID_STATE);
1064
1065 uint32_t cbBuf = _64K; /** @todo Make this configurable? */
1066 void *pvBuf = RTMemAlloc(cbBuf);
1067 if (!pvBuf)
1068 return VERR_NO_MEMORY;
1069
1070 RTCString strPath = pObj->GetDestPathAbs();
1071
1072 LogFlowFunc(("strFile=%s (%zu), cbSize=%RU64, fMode=0x%x\n", strPath.c_str(), strPath.length(),
1073 pObj->GetSize(), pObj->GetMode()));
1074
1075 VBoxClipboardWriteFileHdrMsg MsgHdr;
1076 RT_ZERO(MsgHdr);
1077
1078 VBGL_HGCM_HDR_INIT(&MsgHdr.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_HDR, 6);
1079 MsgHdr.uContext.SetUInt32(0); /* Context ID; unused at the moment. */
1080 MsgHdr.pvName.SetPtr((void *)strPath.c_str(), (uint32_t)(strPath.length() + 1));
1081 MsgHdr.cbName.SetUInt32((uint32_t)(strPath.length() + 1));
1082 MsgHdr.uFlags.SetUInt32(0); /* Flags; unused at the moment. */
1083 MsgHdr.fMode.SetUInt32(pObj->GetMode()); /* File mode */
1084 MsgHdr.cbTotal.SetUInt64(pObj->GetSize()); /* File size (in bytes). */
1085
1086 int rc = VbglR3HGCMCall(&MsgHdr.hdr, sizeof(MsgHdr));
1087
1088 LogFlowFunc(("Sending file header resulted in %Rrc\n", rc));
1089
1090 if (RT_SUCCESS(rc))
1091 {
1092 /*
1093 * Send the actual file data, chunk by chunk.
1094 */
1095 VBoxClipboardWriteFileDataMsg Msg;
1096 RT_ZERO(Msg);
1097
1098 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_FILE_DATA, 5);
1099 Msg.uContext.SetUInt32(0);
1100 Msg.pvChecksum.SetPtr(NULL, 0);
1101 Msg.cbChecksum.SetUInt32(0);
1102
1103 uint64_t cbToReadTotal = pObj->GetSize();
1104 uint64_t cbWrittenTotal = 0;
1105 while (cbToReadTotal)
1106 {
1107 uint32_t cbToRead = RT_MIN(cbToReadTotal, cbBuf);
1108 uint32_t cbRead = 0;
1109 if (cbToRead)
1110 rc = pObj->Read(pvBuf, cbToRead, &cbRead);
1111
1112 LogFlowFunc(("cbToReadTotal=%RU64, cbToRead=%RU32, cbRead=%RU32, rc=%Rrc\n",
1113 cbToReadTotal, cbToRead, cbRead, rc));
1114
1115 if ( RT_SUCCESS(rc)
1116 && cbRead)
1117 {
1118 Msg.pvData.SetPtr(pvBuf, cbRead);
1119 Msg.cbData.SetUInt32(cbRead);
1120 /** @todo Calculate + set checksums. */
1121
1122 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1123 }
1124
1125 if (RT_FAILURE(rc))
1126 {
1127 LogFlowFunc(("Reading failed with rc=%Rrc\n", rc));
1128 break;
1129 }
1130
1131 Assert(cbRead <= cbToReadTotal);
1132 cbToReadTotal -= cbRead;
1133 cbWrittenTotal += cbRead;
1134
1135 LogFlowFunc(("%RU64/%RU64 -- %RU8%%\n", cbWrittenTotal, pObj->GetSize(), cbWrittenTotal * 100 / pObj->GetSize()));
1136 };
1137 }
1138
1139 RTMemFree(pvBuf);
1140
1141 LogFlowFuncLeaveRC(rc);
1142 return rc;
1143}
1144
1145/**
1146 * Utility function to write an URI object from guest to the host.
1147 *
1148 * @returns IPRT status code.
1149 * @param idClient The client id returned by VbglR3ClipboardConnect().
1150 * @param pObj URI object to send from guest to the host.
1151 */
1152static int vbglR3ClipboardWriteURIObject(HGCMCLIENTID idClient, SharedClipboardURIObject *pObj)
1153{
1154 AssertPtrReturn(pObj, VERR_INVALID_POINTER);
1155
1156 int rc;
1157
1158 switch (pObj->GetType())
1159 {
1160 case SharedClipboardURIObject::Type_Directory:
1161 rc = vbglR3ClipboardWriteDir(idClient, pObj);
1162 break;
1163
1164 case SharedClipboardURIObject::Type_File:
1165 rc = vbglR3ClipboardWriteFile(idClient, pObj);
1166 break;
1167
1168 default:
1169 AssertMsgFailed(("Object type %ld not implemented\n", pObj->GetType()));
1170 rc = VERR_NOT_IMPLEMENTED;
1171 break;
1172 }
1173
1174 return rc;
1175}
1176
1177/**
1178 * Utility function to write URI data from guest to the host.
1179 *
1180 * @returns IPRT status code.
1181 * @param idClient The client id returned by VbglR3ClipboardConnect().
1182 * @param pvData Block to URI data to send.
1183 * @param cbData Size (in bytes) of URI data to send.
1184 */
1185static int vbglR3ClipboardWriteURIData(HGCMCLIENTID idClient, const void *pvData, size_t cbData)
1186{
1187 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1188 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1189
1190 RTCList<RTCString> lstPaths =
1191 RTCString((const char *)pvData, cbData).split("\r\n");
1192
1193 /** @todo Add symlink support (SHAREDCLIPBOARDURILIST_FLAGS_RESOLVE_SYMLINKS) here. */
1194 /** @todo Add lazy loading (SHAREDCLIPBOARDURILIST_FLAGS_LAZY) here. */
1195 uint32_t fFlags = SHAREDCLIPBOARDURILIST_FLAGS_KEEP_OPEN;
1196
1197 SharedClipboardURIList lstURI;
1198 int rc = lstURI.AppendURIPathsFromList(lstPaths, fFlags);
1199 if (RT_SUCCESS(rc))
1200 {
1201 /*
1202 * Send the (meta) data; in case of URIs it's the (non-recursive) file/directory
1203 * URI list the host needs to know upfront to set up the Shared Clipboard operation.
1204 */
1205 RTCString strRootDest = lstURI.GetRootEntries();
1206 if (strRootDest.isNotEmpty())
1207 {
1208 void *pvURIList = (void *)strRootDest.c_str(); /* URI root list. */
1209 uint32_t cbURLIist = (uint32_t)strRootDest.length() + 1; /* Include string termination. */
1210
1211 /* The total size also contains the size of the meta data. */
1212 uint64_t cbTotal = cbURLIist;
1213 cbTotal += lstURI.GetTotalBytes();
1214
1215 /* We're going to send an URI list in text format. */
1216 const char szMetaFmt[] = "text/uri-list";
1217 const uint32_t cbMetaFmt = (uint32_t)strlen(szMetaFmt) + 1; /* Include termination. */
1218
1219 VBOXCLIPBOARDDATAHDR dataHdr;
1220 dataHdr.uFlags = 0; /* Flags not used yet. */
1221 dataHdr.cbTotal = cbTotal;
1222 dataHdr.cbMeta = cbURLIist;
1223 dataHdr.pvMetaFmt = (void *)szMetaFmt;
1224 dataHdr.cbMetaFmt = cbMetaFmt;
1225 dataHdr.cObjects = lstURI.GetTotalCount();
1226
1227 rc = vbglR3ClipboardWriteDataInternal(idClient,
1228 pvURIList, cbURLIist, &dataHdr);
1229 }
1230 else
1231 rc = VERR_INVALID_PARAMETER;
1232 }
1233
1234 if (RT_SUCCESS(rc))
1235 {
1236 while (!lstURI.IsEmpty())
1237 {
1238 SharedClipboardURIObject *pNextObj = lstURI.First();
1239
1240 rc = vbglR3ClipboardWriteURIObject(idClient, pNextObj);
1241 if (RT_FAILURE(rc))
1242 break;
1243
1244 lstURI.RemoveFirst();
1245 }
1246 }
1247
1248 return rc;
1249}
1250
1251/**
1252 * Writes an error to the host.
1253 *
1254 * @returns IPRT status code.
1255 * @param idClient The client id returned by VbglR3ClipboardConnect().
1256 * @param rcErr Error (IPRT-style) to send.
1257 */
1258static int vbglR3ClipboardWriteErrorInternal(HGCMCLIENTID idClient, int rcErr)
1259{
1260 VBoxClipboardWriteErrorMsg Msg;
1261 RT_ZERO(Msg);
1262
1263 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHARED_CLIPBOARD_FN_WRITE_ERROR, 2);
1264 /** @todo Context ID not used yet. */
1265 Msg.uContext.SetUInt32(0);
1266 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
1267
1268 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1269
1270 /*
1271 * Never return an error if the host did not accept the error at the current
1272 * time. This can be due to the host not having any appropriate callbacks
1273 * set which would handle that error.
1274 *
1275 * bird: Looks like VERR_NOT_SUPPORTED is what the host will return if it
1276 * doesn't an appropriate callback. The code used to ignore ALL errors
1277 * the host would return, also relevant ones.
1278 */
1279 if (RT_FAILURE(rc))
1280 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
1281 if (rc == VERR_NOT_SUPPORTED)
1282 rc = VINF_SUCCESS;
1283
1284 return rc;
1285}
1286
1287/**
1288 * Writes an error back to the host.
1289 *
1290 * @returns IPRT status code.
1291 * @param idClient The client id returned by VbglR3ClipboardConnect().
1292 * @param rcErr Error (IPRT-style) to send.
1293 */
1294VBGLR3DECL(int) vbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
1295{
1296 return vbglR3ClipboardWriteErrorInternal(idClient, rcErr);
1297}
1298#endif /* VBOX_WITH_SHARED_CLIPBOARD_URI_LIST */
1299
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