VirtualBox

source: vbox/trunk/src/VBox/HostServices/SharedClipboard/VBoxSharedClipboardSvc-transfers.cpp@ 80990

Last change on this file since 80990 was 80990, checked in by vboxsync, 5 years ago

Shared Clipboard/Transfers: Update.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.0 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 80990 2019-09-25 06:20:09Z vboxsync $ */
2/** @file
3 * Shared Clipboard Service - Internal code for transfer (list) handling.
4 */
5
6/*
7 * Copyright (C) 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
18
19/*********************************************************************************************************************************
20* Header Files *
21*********************************************************************************************************************************/
22#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
23#include <VBox/log.h>
24
25#include <VBox/err.h>
26
27#include <VBox/GuestHost/clipboard-helper.h>
28#include <VBox/HostServices/VBoxClipboardSvc.h>
29#include <VBox/HostServices/VBoxClipboardExt.h>
30
31#include <iprt/dir.h>
32#include <iprt/file.h>
33#include <iprt/path.h>
34
35#include "VBoxSharedClipboardSvc-internal.h"
36#include "VBoxSharedClipboardSvc-transfers.h"
37
38
39/*********************************************************************************************************************************
40* Externals *
41*********************************************************************************************************************************/
42extern SHCLEXTSTATE g_ExtState;
43extern PVBOXHGCMSVCHELPERS g_pHelpers;
44extern ClipboardClientQueue g_listClientsDeferred;
45
46
47/*********************************************************************************************************************************
48* Prototypes *
49*********************************************************************************************************************************/
50static int sharedClipboardSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
51 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms);
52static int sharedClipboardSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
53 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList);
54
55
56/*********************************************************************************************************************************
57* Provider implementation *
58*********************************************************************************************************************************/
59
60DECLCALLBACK(int) sharedClipboardSvcTransferIfaceOpen(PSHCLPROVIDERCTX pCtx)
61{
62 RT_NOREF(pCtx);
63
64 LogFlowFuncLeave();
65 return VINF_SUCCESS;
66}
67
68DECLCALLBACK(int) sharedClipboardSvcTransferIfaceClose(PSHCLPROVIDERCTX pCtx)
69{
70 RT_NOREF(pCtx);
71
72 LogFlowFuncLeave();
73 return VINF_SUCCESS;
74}
75
76DECLCALLBACK(int) sharedClipboardSvcTransferIfaceGetRoots(PSHCLPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)
77{
78 LogFlowFuncEnter();
79
80 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
81 AssertPtr(pClient);
82
83 int rc;
84
85 PSHCLCLIENTMSG pMsgHdr = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
86 VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
87 if (pMsgHdr)
88 {
89 SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
90
91 HGCMSvcSetU32(&pMsgHdr->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
92 pCtx->pTransfer->State.uID, uEvent));
93 HGCMSvcSetU32(&pMsgHdr->paParms[1], 0 /* fRoots */);
94
95 rc = sharedClipboardSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
96 if (RT_SUCCESS(rc))
97 {
98 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
99 AssertRC(rc2);
100
101 rc = sharedClipboardSvcClientWakeup(pClient);
102 if (RT_SUCCESS(rc))
103 {
104 PSHCLEVENTPAYLOAD pPayloadHdr;
105 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
106 pCtx->pTransfer->uTimeoutMs, &pPayloadHdr);
107 if (RT_SUCCESS(rc))
108 {
109 PSHCLROOTLISTHDR pSrcRootListHdr = (PSHCLROOTLISTHDR)pPayloadHdr->pvData;
110 Assert(pPayloadHdr->cbData == sizeof(SHCLROOTLISTHDR));
111
112 LogFlowFunc(("cRoots=%RU32, fRoots=0x%x\n", pSrcRootListHdr->cRoots, pSrcRootListHdr->fRoots));
113
114 PSHCLROOTLIST pRootList = SharedClipboardTransferRootListAlloc();
115 if (pRootList)
116 {
117 if (pSrcRootListHdr->cRoots)
118 {
119 pRootList->paEntries =
120 (PSHCLROOTLISTENTRY)RTMemAllocZ(pSrcRootListHdr->cRoots * sizeof(SHCLROOTLISTENTRY));
121
122 if (pRootList->paEntries)
123 {
124 for (uint32_t i = 0; i < pSrcRootListHdr->cRoots; i++)
125 {
126 PSHCLCLIENTMSG pMsgEntry = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ,
127 VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
128
129 uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
130
131 HGCMSvcSetU32(&pMsgEntry->paParms[0],
132 VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uClientID,
133 pCtx->pTransfer->State.uID, uEvent));
134 HGCMSvcSetU32(&pMsgEntry->paParms[1], 0 /* fRoots */);
135 HGCMSvcSetU32(&pMsgEntry->paParms[2], i /* uIndex */);
136
137 rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
138 AssertRC(rc2);
139
140 rc = sharedClipboardSvcMsgAdd(pClient, pMsgEntry, true /* fAppend */);
141 if (RT_FAILURE(rc))
142 break;
143
144 PSHCLEVENTPAYLOAD pPayloadEntry;
145 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
146 pCtx->pTransfer->uTimeoutMs, &pPayloadEntry);
147 if (RT_FAILURE(rc))
148 break;
149
150 PSHCLROOTLISTENTRY pSrcRootListEntry = (PSHCLROOTLISTENTRY)pPayloadEntry->pvData;
151 Assert(pPayloadEntry->cbData == sizeof(SHCLROOTLISTENTRY));
152
153 rc = SharedClipboardTransferListEntryCopy(&pRootList->paEntries[i], pSrcRootListEntry);
154
155 SharedClipboardPayloadFree(pPayloadEntry);
156
157 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
158
159 if (RT_FAILURE(rc))
160 break;
161 }
162 }
163 else
164 rc = VERR_NO_MEMORY;
165 }
166
167 if (RT_SUCCESS(rc))
168 {
169 pRootList->Hdr.cRoots = pSrcRootListHdr->cRoots;
170 pRootList->Hdr.fRoots = 0; /** @todo Implement this. */
171
172 *ppRootList = pRootList;
173 }
174 else
175 SharedClipboardTransferRootListFree(pRootList);
176
177 SharedClipboardPayloadFree(pPayloadHdr);
178 }
179 else
180 rc = VERR_NO_MEMORY;
181 }
182 }
183
184 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
185 }
186 }
187 else
188 rc = VERR_NO_MEMORY;
189
190 LogFlowFuncLeave();
191 return rc;
192}
193
194DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListOpen(PSHCLPROVIDERCTX pCtx,
195 PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)
196{
197 LogFlowFuncEnter();
198
199 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
200 AssertPtr(pClient);
201
202 int rc;
203
204 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN,
205 VBOX_SHCL_CPARMS_LIST_OPEN);
206 if (pMsg)
207 {
208 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
209
210 pMsg->Ctx.uContextID = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
211 uEvent);
212
213 rc = sharedClipboardSvcTransferSetListOpen(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, pOpenParms);
214 if (RT_SUCCESS(rc))
215 {
216 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
217 if (RT_SUCCESS(rc))
218 {
219 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
220 AssertRC(rc2);
221
222 rc = sharedClipboardSvcClientWakeup(pClient);
223 if (RT_SUCCESS(rc))
224 {
225 PSHCLEVENTPAYLOAD pPayload;
226 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
227 if (RT_SUCCESS(rc))
228 {
229 Assert(pPayload->cbData == sizeof(SHCLREPLY));
230
231 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
232 AssertPtr(pReply);
233
234 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN);
235
236 *phList = pReply->u.ListOpen.uHandle;
237
238 SharedClipboardPayloadFree(pPayload);
239 }
240 }
241
242 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
243 }
244 }
245 }
246 else
247 rc = VERR_NO_MEMORY;
248
249 LogFlowFuncLeaveRC(rc);
250 return rc;
251}
252
253DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListClose(PSHCLPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
254{
255 LogFlowFuncEnter();
256
257 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
258 AssertPtr(pClient);
259
260 int rc;
261
262 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE,
263 VBOX_SHCL_CPARMS_LIST_CLOSE);
264 if (pMsg)
265 {
266 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
267
268 pMsg->Ctx.uContextID = VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID, pCtx->pTransfer->State.uID,
269 uEvent);
270
271 rc = sharedClipboardSvcTransferSetListClose(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, hList);
272 if (RT_SUCCESS(rc))
273 {
274 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
275 if (RT_SUCCESS(rc))
276 {
277 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
278 AssertRC(rc2);
279
280 rc = sharedClipboardSvcClientWakeup(pClient);
281 if (RT_SUCCESS(rc))
282 {
283 PSHCLEVENTPAYLOAD pPayload;
284 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
285 if (RT_SUCCESS(rc))
286 SharedClipboardPayloadFree(pPayload);
287 }
288
289 SharedClipboardEventUnregister(&pCtx->pTransfer->Events, uEvent);
290 }
291 }
292 }
293 else
294 rc = VERR_NO_MEMORY;
295
296 LogFlowFuncLeaveRC(rc);
297 return rc;
298}
299
300DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListHdrRead(PSHCLPROVIDERCTX pCtx,
301 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
302{
303 LogFlowFuncEnter();
304
305 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
306 AssertPtr(pClient);
307
308 int rc;
309
310 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ,
311 VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
312 if (pMsg)
313 {
314 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
315
316 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
317 pCtx->pTransfer->State.uID, uEvent));
318 HGCMSvcSetU64(&pMsg->paParms[1], hList);
319 HGCMSvcSetU32(&pMsg->paParms[2], 0 /* fFlags */);
320
321 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
322 if (RT_SUCCESS(rc))
323 {
324 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
325 AssertRC(rc2);
326
327 rc = sharedClipboardSvcClientWakeup(pClient);
328 if (RT_SUCCESS(rc))
329 {
330 PSHCLEVENTPAYLOAD pPayload;
331 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent,
332 pCtx->pTransfer->uTimeoutMs, &pPayload);
333 if (RT_SUCCESS(rc))
334 {
335 Assert(pPayload->cbData == sizeof(SHCLLISTHDR));
336
337 *pListHdr = *(PSHCLLISTHDR)pPayload->pvData;
338
339 SharedClipboardPayloadFree(pPayload);
340 }
341 }
342 }
343 }
344 else
345 rc = VERR_NO_MEMORY;
346
347 LogFlowFuncLeaveRC(rc);
348 return rc;
349}
350
351DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListHdrWrite(PSHCLPROVIDERCTX pCtx,
352 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
353{
354 RT_NOREF(pCtx, hList, pListHdr);
355
356 LogFlowFuncEnter();
357
358 return VERR_NOT_IMPLEMENTED;
359}
360
361DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListEntryRead(PSHCLPROVIDERCTX pCtx,
362 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
363{
364 LogFlowFuncEnter();
365
366 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
367 AssertPtr(pClient);
368
369 int rc;
370
371 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ,
372 VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
373 if (pMsg)
374 {
375 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
376
377 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
378 pCtx->pTransfer->State.uID, uEvent));
379 HGCMSvcSetU64(&pMsg->paParms[1], hList);
380 HGCMSvcSetU32(&pMsg->paParms[2], 0 /* fInfo */);
381
382 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
383 if (RT_SUCCESS(rc))
384 {
385 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
386 AssertRC(rc2);
387
388 rc = sharedClipboardSvcClientWakeup(pClient);
389 if (RT_SUCCESS(rc))
390 {
391 PSHCLEVENTPAYLOAD pPayload;
392 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
393 if (RT_SUCCESS(rc))
394 {
395 Assert(pPayload->cbData == sizeof(SHCLLISTENTRY));
396
397 rc = SharedClipboardTransferListEntryCopy(pListEntry, (PSHCLLISTENTRY)pPayload->pvData);
398
399 SharedClipboardPayloadFree(pPayload);
400 }
401 }
402 }
403 }
404 else
405 rc = VERR_NO_MEMORY;
406
407 LogFlowFuncLeaveRC(rc);
408 return rc;
409}
410
411DECLCALLBACK(int) sharedClipboardSvcTransferIfaceListEntryWrite(PSHCLPROVIDERCTX pCtx,
412 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
413{
414 RT_NOREF(pCtx, hList, pListEntry);
415
416 LogFlowFuncEnter();
417
418 return VERR_NOT_IMPLEMENTED;
419}
420
421int sharedClipboardSvcTransferIfaceObjOpen(PSHCLPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
422 PSHCLOBJHANDLE phObj)
423{
424 LogFlowFuncEnter();
425
426 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
427 AssertPtr(pClient);
428
429 int rc;
430
431 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN,
432 VBOX_SHCL_CPARMS_OBJ_OPEN);
433 if (pMsg)
434 {
435 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
436
437 LogFlowFunc(("pszPath=%s, fCreate=0x%x\n", pCreateParms->pszPath, pCreateParms->fCreate));
438
439 const uint32_t cbPath = (uint32_t)strlen(pCreateParms->pszPath) + 1; /* Include terminating zero */
440
441 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
442 pCtx->pTransfer->State.uID, uEvent));
443 HGCMSvcSetU64(&pMsg->paParms[1], 0); /* uHandle */
444 HGCMSvcSetU32(&pMsg->paParms[2], cbPath);
445 HGCMSvcSetPv (&pMsg->paParms[3], pCreateParms->pszPath, cbPath);
446 HGCMSvcSetU32(&pMsg->paParms[4], pCreateParms->fCreate);
447
448 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
449 if (RT_SUCCESS(rc))
450 {
451 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
452 AssertRC(rc2);
453
454 rc = sharedClipboardSvcClientWakeup(pClient);
455 if (RT_SUCCESS(rc))
456 {
457 PSHCLEVENTPAYLOAD pPayload;
458 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
459 if (RT_SUCCESS(rc))
460 {
461 Assert(pPayload->cbData == sizeof(SHCLREPLY));
462
463 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
464 AssertPtr(pReply);
465
466 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN);
467
468 *phObj = pReply->u.ObjOpen.uHandle;
469
470 SharedClipboardPayloadFree(pPayload);
471 }
472 }
473 }
474 }
475 else
476 rc = VERR_NO_MEMORY;
477
478 LogFlowFuncLeaveRC(rc);
479 return rc;
480}
481
482int sharedClipboardSvcTransferIfaceObjClose(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
483{
484 LogFlowFuncEnter();
485
486 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
487 AssertPtr(pClient);
488
489 int rc;
490
491 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE,
492 VBOX_SHCL_CPARMS_OBJ_CLOSE);
493 if (pMsg)
494 {
495 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
496
497 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
498 pCtx->pTransfer->State.uID, uEvent));
499 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
500
501 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
502 if (RT_SUCCESS(rc))
503 {
504 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
505 AssertRC(rc2);
506
507 rc = sharedClipboardSvcClientWakeup(pClient);
508 if (RT_SUCCESS(rc))
509 {
510 PSHCLEVENTPAYLOAD pPayload;
511 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
512 if (RT_SUCCESS(rc))
513 {
514 Assert(pPayload->cbData == sizeof(SHCLREPLY));
515
516#ifdef VBOX_STRICT
517 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
518 AssertPtr(pReply);
519
520 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE);
521#endif
522
523 SharedClipboardPayloadFree(pPayload);
524 }
525 }
526 }
527 }
528 else
529 rc = VERR_NO_MEMORY;
530
531 LogFlowFuncLeaveRC(rc);
532 return rc;
533}
534
535int sharedClipboardSvcTransferIfaceObjRead(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
536 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbRead)
537{
538 LogFlowFuncEnter();
539
540 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
541 AssertPtr(pClient);
542
543 int rc;
544
545 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ,
546 VBOX_SHCL_CPARMS_OBJ_READ_REQ);
547 if (pMsg)
548 {
549 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
550
551 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
552 pCtx->pTransfer->State.uID, uEvent));
553 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
554 HGCMSvcSetU32(&pMsg->paParms[2], cbData);
555 HGCMSvcSetU32(&pMsg->paParms[3], fFlags);
556
557 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
558 if (RT_SUCCESS(rc))
559 {
560 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
561 AssertRC(rc2);
562
563 rc = sharedClipboardSvcClientWakeup(pClient);
564 if (RT_SUCCESS(rc))
565 {
566 PSHCLEVENTPAYLOAD pPayload;
567 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
568 if (RT_SUCCESS(rc))
569 {
570 Assert(pPayload->cbData == sizeof(SHCLOBJDATACHUNK));
571
572 PSHCLOBJDATACHUNK pDataChunk = (PSHCLOBJDATACHUNK)pPayload->pvData;
573 AssertPtr(pDataChunk);
574
575 const uint32_t cbRead = RT_MIN(cbData, pDataChunk->cbData);
576
577 memcpy(pvData, pDataChunk->pvData, cbRead);
578
579 if (pcbRead)
580 *pcbRead = cbRead;
581
582 SharedClipboardPayloadFree(pPayload);
583 }
584 }
585 }
586 }
587 else
588 rc = VERR_NO_MEMORY;
589
590 LogFlowFuncLeaveRC(rc);
591 return rc;
592}
593
594int sharedClipboardSvcTransferIfaceObjWrite(PSHCLPROVIDERCTX pCtx, SHCLOBJHANDLE hObj,
595 void *pvData, uint32_t cbData, uint32_t fFlags, uint32_t *pcbWritten)
596{
597 LogFlowFuncEnter();
598
599 PSHCLCLIENT pClient = (PSHCLCLIENT)pCtx->pvUser;
600 AssertPtr(pClient);
601
602 int rc;
603
604 PSHCLCLIENTMSG pMsg = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE,
605 VBOX_SHCL_CPARMS_OBJ_WRITE);
606 if (pMsg)
607 {
608 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pCtx->pTransfer->Events);
609
610 HGCMSvcSetU32(&pMsg->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
611 pCtx->pTransfer->State.uID, uEvent));
612 HGCMSvcSetU64(&pMsg->paParms[1], hObj);
613 HGCMSvcSetU64(&pMsg->paParms[2], cbData);
614 HGCMSvcSetU64(&pMsg->paParms[3], fFlags);
615
616 rc = sharedClipboardSvcMsgAdd(pClient, pMsg, true /* fAppend */);
617 if (RT_SUCCESS(rc))
618 {
619 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
620 AssertRC(rc2);
621
622 rc = sharedClipboardSvcClientWakeup(pClient);
623 if (RT_SUCCESS(rc))
624 {
625 PSHCLEVENTPAYLOAD pPayload;
626 rc = SharedClipboardEventWait(&pCtx->pTransfer->Events, uEvent, pCtx->pTransfer->uTimeoutMs, &pPayload);
627 if (RT_SUCCESS(rc))
628 {
629 const uint32_t cbRead = RT_MIN(cbData, pPayload->cbData);
630
631 memcpy(pvData, pPayload->pvData, cbRead);
632
633 if (pcbWritten)
634 *pcbWritten = cbRead;
635
636 SharedClipboardPayloadFree(pPayload);
637 }
638 }
639 }
640 }
641 else
642 rc = VERR_NO_MEMORY;
643
644 LogFlowFuncLeaveRC(rc);
645 return rc;
646}
647
648
649/*********************************************************************************************************************************
650* HGCM getters / setters *
651*********************************************************************************************************************************/
652
653/**
654 * Gets a transfer message reply from HGCM service parameters.
655 *
656 * @returns VBox status code.
657 * @param cParms Number of HGCM parameters supplied in \a paParms.
658 * @param paParms Array of HGCM parameters.
659 * @param pReply Where to store the reply.
660 */
661static int sharedClipboardSvcTransferGetReply(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
662 PSHCLREPLY pReply)
663{
664 int rc;
665
666 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
667 {
668 uint32_t cbPayload = 0;
669
670 /* paParms[0] has the context ID. */
671 rc = HGCMSvcGetU32(&paParms[1], &pReply->uType);
672 if (RT_SUCCESS(rc))
673 rc = HGCMSvcGetU32(&paParms[2], &pReply->rc);
674 if (RT_SUCCESS(rc))
675 rc = HGCMSvcGetU32(&paParms[3], &cbPayload);
676 if (RT_SUCCESS(rc))
677 {
678 rc = HGCMSvcGetPv(&paParms[4], &pReply->pvPayload, &pReply->cbPayload);
679 AssertReturn(cbPayload == pReply->cbPayload, VERR_INVALID_PARAMETER);
680 }
681
682 if (RT_SUCCESS(rc))
683 {
684 rc = VERR_INVALID_PARAMETER; /* Play safe. */
685
686 switch (pReply->uType)
687 {
688 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
689 {
690 if (cParms >= 6)
691 rc = HGCMSvcGetU32(&paParms[5], &pReply->u.TransferStatus.uStatus);
692 break;
693 }
694
695 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
696 {
697 if (cParms >= 6)
698 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ListOpen.uHandle);
699 break;
700 }
701
702 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
703 {
704 if (cParms >= 6)
705 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjOpen.uHandle);
706 break;
707 }
708
709 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
710 {
711 if (cParms >= 6)
712 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjClose.uHandle);
713 break;
714 }
715
716 default:
717 rc = VERR_NOT_SUPPORTED;
718 break;
719 }
720 }
721 }
722 else
723 rc = VERR_INVALID_PARAMETER;
724
725 LogFlowFuncLeaveRC(rc);
726 return rc;
727}
728
729/**
730 * Gets a transfer root list header from HGCM service parameters.
731 *
732 * @returns VBox status code.
733 * @param cParms Number of HGCM parameters supplied in \a paParms.
734 * @param paParms Array of HGCM parameters.
735 * @param pRootLstHdr Where to store the transfer root list header on success.
736 */
737static int sharedClipboardSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
738 PSHCLROOTLISTHDR pRootLstHdr)
739{
740 int rc;
741
742 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR)
743 {
744 rc = HGCMSvcGetU32(&paParms[1], &pRootLstHdr->fRoots);
745 if (RT_SUCCESS(rc))
746 rc = HGCMSvcGetU32(&paParms[2], &pRootLstHdr->cRoots);
747 }
748 else
749 rc = VERR_INVALID_PARAMETER;
750
751 LogFlowFuncLeaveRC(rc);
752 return rc;
753}
754
755/**
756 * Gets a transfer root list entry from HGCM service parameters.
757 *
758 * @returns VBox status code.
759 * @param cParms Number of HGCM parameters supplied in \a paParms.
760 * @param paParms Array of HGCM parameters.
761 * @param pListEntry Where to store the root list entry.
762 */
763static int sharedClipboardSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
764 PSHCLROOTLISTENTRY pListEntry)
765{
766 int rc;
767
768 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY)
769 {
770 rc = HGCMSvcGetU32(&paParms[1], &pListEntry->fInfo);
771 /* Note: paParms[2] contains the entry index, currently being ignored. */
772 if (RT_SUCCESS(rc))
773 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
774 if (RT_SUCCESS(rc))
775 {
776 uint32_t cbInfo;
777 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
778 if (RT_SUCCESS(rc))
779 {
780 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
781 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
782 }
783 }
784 }
785 else
786 rc = VERR_INVALID_PARAMETER;
787
788 LogFlowFuncLeaveRC(rc);
789 return rc;
790}
791
792/**
793 * Gets a transfer list open request from HGCM service parameters.
794 *
795 * @returns VBox status code.
796 * @param cParms Number of HGCM parameters supplied in \a paParms.
797 * @param paParms Array of HGCM parameters.
798 * @param pOpenParms Where to store the open parameters of the request.
799 */
800static int sharedClipboardSvcTransferGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
801 PSHCLLISTOPENPARMS pOpenParms)
802{
803 int rc;
804
805 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
806 {
807 uint32_t cbPath = 0;
808 uint32_t cbFilter = 0;
809
810 rc = HGCMSvcGetU32(&paParms[1], &pOpenParms->fList);
811 if (RT_SUCCESS(rc))
812 rc = HGCMSvcGetU32(&paParms[2], &cbPath);
813 if (RT_SUCCESS(rc))
814 {
815 rc = HGCMSvcGetStr(&paParms[3], &pOpenParms->pszPath, &pOpenParms->cbPath);
816 AssertReturn(cbPath == pOpenParms->cbPath, VERR_INVALID_PARAMETER);
817 }
818 if (RT_SUCCESS(rc))
819 rc = HGCMSvcGetU32(&paParms[4], &cbFilter);
820 if (RT_SUCCESS(rc))
821 {
822 rc = HGCMSvcGetStr(&paParms[5], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
823 AssertReturn(cbFilter == pOpenParms->cbFilter, VERR_INVALID_PARAMETER);
824 }
825
826 if (RT_SUCCESS(rc))
827 {
828 /** @todo Some more validation. */
829 }
830 }
831 else
832 rc = VERR_INVALID_PARAMETER;
833
834 LogFlowFuncLeaveRC(rc);
835 return rc;
836}
837
838/**
839 * Sets a transfer list open request to HGCM service parameters.
840 *
841 * @returns VBox status code.
842 * @param cParms Number of HGCM parameters supplied in \a paParms.
843 * @param paParms Array of HGCM parameters.
844 * @param pMsgCtx Message context to use.
845 * @param pOpenParms List open parameters to set.
846 */
847static int sharedClipboardSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
848 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms)
849{
850 int rc;
851
852 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
853 {
854 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
855 HGCMSvcSetU32(&paParms[1], pOpenParms->fList);
856 HGCMSvcSetU32(&paParms[2], pOpenParms->cbFilter);
857 HGCMSvcSetPv (&paParms[3], pOpenParms->pszFilter, pOpenParms->cbFilter);
858 HGCMSvcSetU32(&paParms[4], pOpenParms->cbPath);
859 HGCMSvcSetPv (&paParms[5], pOpenParms->pszPath, pOpenParms->cbPath);
860 HGCMSvcSetU64(&paParms[6], 0); /* OUT: uHandle */
861
862 rc = VINF_SUCCESS;
863 }
864 else
865 rc = VERR_INVALID_PARAMETER;
866
867 LogFlowFuncLeaveRC(rc);
868 return rc;
869}
870
871/**
872 * Sets a transfer list close request to HGCM service parameters.
873 *
874 * @returns VBox status code.
875 * @param cParms Number of HGCM parameters supplied in \a paParms.
876 * @param paParms Array of HGCM parameters.
877 * @param pMsgCtx Message context to use.
878 * @param hList Handle of list to close.
879 */
880static int sharedClipboardSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
881 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList)
882{
883 int rc;
884
885 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
886 {
887 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
888 HGCMSvcSetU64(&paParms[1], hList);
889
890 rc = VINF_SUCCESS;
891 }
892 else
893 rc = VERR_INVALID_PARAMETER;
894
895 LogFlowFuncLeaveRC(rc);
896 return rc;
897}
898
899/**
900 * Gets a transfer list header from HGCM service parameters.
901 *
902 * @returns VBox status code.
903 * @param cParms Number of HGCM parameters supplied in \a paParms.
904 * @param paParms Array of HGCM parameters.
905 * @param phList Where to store the list handle.
906 * @param pListHdr Where to store the list header.
907 */
908static int sharedClipboardSvcTransferGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
909 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
910{
911 int rc;
912
913 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
914 {
915 rc = HGCMSvcGetU64(&paParms[1], phList);
916 /* Note: Flags (paParms[2]) not used here. */
917 if (RT_SUCCESS(rc))
918 rc = HGCMSvcGetU32(&paParms[3], &pListHdr->fFeatures);
919 if (RT_SUCCESS(rc))
920 rc = HGCMSvcGetU64(&paParms[4], &pListHdr->cTotalObjects);
921 if (RT_SUCCESS(rc))
922 rc = HGCMSvcGetU64(&paParms[5], &pListHdr->cbTotalSize);
923
924 if (RT_SUCCESS(rc))
925 {
926 /** @todo Validate pvMetaFmt + cbMetaFmt. */
927 /** @todo Validate header checksum. */
928 }
929 }
930 else
931 rc = VERR_INVALID_PARAMETER;
932
933 LogFlowFuncLeaveRC(rc);
934 return rc;
935}
936
937#if 0
938/**
939 * Sets a transfer list header to HGCM service parameters.
940 *
941 * @returns VBox status code.
942 * @param cParms Number of HGCM parameters supplied in \a paParms.
943 * @param paParms Array of HGCM parameters.
944 * @param pMsgCtx Message context to use.
945 * @param pListHdr Pointer to data to set to the HGCM parameters.
946 */
947static int sharedClipboardSvcTransferSetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
948 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTHDR pListHdr)
949{
950 int rc;
951
952 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
953 {
954 /** @todo Set pvMetaFmt + cbMetaFmt. */
955 /** @todo Calculate header checksum. */
956
957 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
958 HGCMSvcSetU32(&paParms[1], pListHdr->fFeatures);
959 HGCMSvcSetU32(&paParms[2], 0 /* Features, will be returned on success */);
960 HGCMSvcSetU64(&paParms[3], pListHdr->cTotalObjects);
961 HGCMSvcSetU64(&paParms[4], pListHdr->cbTotalSize);
962
963 rc = VINF_SUCCESS;
964 }
965 else
966 rc = VERR_INVALID_PARAMETER;
967
968 LogFlowFuncLeaveRC(rc);
969 return rc;
970}
971#endif
972
973/**
974 * Gets a transfer list entry from HGCM service parameters.
975 *
976 * @returns VBox status code.
977 * @param cParms Number of HGCM parameters supplied in \a paParms.
978 * @param paParms Array of HGCM parameters.
979 * @param phList Where to store the list handle.
980 * @param pListEntry Where to store the list entry.
981 */
982static int sharedClipboardSvcTransferGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
983 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
984{
985 int rc;
986
987 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
988 {
989 rc = HGCMSvcGetU64(&paParms[1], phList);
990 if (RT_SUCCESS(rc))
991 rc = HGCMSvcGetU32(&paParms[2], &pListEntry->fInfo);
992 if (RT_SUCCESS(rc))
993 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
994 if (RT_SUCCESS(rc))
995 {
996 uint32_t cbInfo;
997 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
998 if (RT_SUCCESS(rc))
999 {
1000 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1001 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1002 }
1003 }
1004
1005 if (RT_SUCCESS(rc))
1006 {
1007 if (!SharedClipboardTransferListEntryIsValid(pListEntry))
1008 rc = VERR_INVALID_PARAMETER;
1009 }
1010 }
1011 else
1012 rc = VERR_INVALID_PARAMETER;
1013
1014 LogFlowFuncLeaveRC(rc);
1015 return rc;
1016}
1017
1018#if 0
1019/**
1020 * Sets a transfer data chunk to HGCM service parameters.
1021 *
1022 * @returns VBox status code.
1023 * @param cParms Number of HGCM parameters supplied in \a paParms.
1024 * @param paParms Array of HGCM parameters.
1025 * @param pMsgCtx Message context to use.
1026 * @param pListEntry Pointer to data to set to the HGCM parameters.
1027 */
1028static int sharedClipboardSvcTransferSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1029 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTENTRY pListEntry)
1030{
1031 int rc;
1032
1033 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1034 {
1035 /** @todo Calculate chunk checksum. */
1036
1037 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
1038 HGCMSvcSetU32(&paParms[1], pListEntry->fInfo);
1039 HGCMSvcSetU32(&paParms[2], pListEntry->cbInfo);
1040 HGCMSvcSetPv (&paParms[3], pListEntry->pvInfo, pListEntry->cbInfo);
1041
1042 rc = VINF_SUCCESS;
1043 }
1044 else
1045 rc = VERR_INVALID_PARAMETER;
1046
1047 LogFlowFuncLeaveRC(rc);
1048 return rc;
1049}
1050#endif
1051
1052/**
1053 * Gets a transfer object data chunk from HGCM service parameters.
1054 *
1055 * @returns VBox status code.
1056 * @param cParms Number of HGCM parameters supplied in \a paParms.
1057 * @param paParms Array of HGCM parameters.
1058 * @param pDataChunk Where to store the object data chunk data.
1059 */
1060static int sharedClipboardSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM paParms[], PSHCLOBJDATACHUNK pDataChunk)
1061{
1062 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1063 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1064
1065 int rc;
1066
1067 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1068 {
1069 rc = HGCMSvcGetU64(&paParms[1], &pDataChunk->uHandle);
1070 if (RT_SUCCESS(rc))
1071 {
1072 uint32_t cbData;
1073 rc = HGCMSvcGetU32(&paParms[2], &cbData);
1074 if (RT_SUCCESS(rc))
1075 {
1076 rc = HGCMSvcGetPv(&paParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1077 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
1078
1079 /** @todo Implement checksum handling. */
1080 }
1081 }
1082 }
1083 else
1084 rc = VERR_INVALID_PARAMETER;
1085
1086 LogFlowFuncLeaveRC(rc);
1087 return rc;
1088}
1089
1090/**
1091 * Gets a transfer error from HGCM service parameters.
1092 *
1093 * @returns VBox status code.
1094 * @param cParms Number of HGCM parameters supplied in \a paParms.
1095 * @param paParms Array of HGCM parameters.
1096 * @param pRc Where to store the received error code.
1097 */
1098static int sharedClipboardSvcTransferGetError(uint32_t cParms, VBOXHGCMSVCPARM paParms[], int *pRc)
1099{
1100 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1101 AssertPtrReturn(pRc, VERR_INVALID_PARAMETER);
1102
1103 int rc;
1104
1105 if (cParms == VBOX_SHCL_CPARMS_ERROR)
1106 {
1107 rc = HGCMSvcGetU32(&paParms[1], (uint32_t *)pRc); /** @todo int vs. uint32_t !!! */
1108 }
1109 else
1110 rc = VERR_INVALID_PARAMETER;
1111
1112 LogFlowFuncLeaveRC(rc);
1113 return rc;
1114}
1115
1116/**
1117 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1118 *
1119 * @returns VBox status code.
1120 * @param pClient Pointer to associated client.
1121 * @param pTransfer Pointer to transfer to handle guest reply for.
1122 * @param cParms Number of function parameters supplied.
1123 * @param paParms Array function parameters supplied.
1124 */
1125static int sharedClipboardSvcTransferHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer,
1126 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1127{
1128 RT_NOREF(pClient);
1129
1130 int rc;
1131
1132 uint32_t cbReply = sizeof(SHCLREPLY);
1133 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1134 if (pReply)
1135 {
1136 rc = sharedClipboardSvcTransferGetReply(cParms, paParms, pReply);
1137 if (RT_SUCCESS(rc))
1138 {
1139 PSHCLEVENTPAYLOAD pPayload
1140 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1141 if (pPayload)
1142 {
1143 pPayload->pvData = pReply;
1144 pPayload->cbData = cbReply;
1145
1146 switch (pReply->uType)
1147 {
1148 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
1149 RT_FALL_THROUGH();
1150 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
1151 RT_FALL_THROUGH();
1152 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
1153 RT_FALL_THROUGH();
1154 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
1155 RT_FALL_THROUGH();
1156 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
1157 {
1158 uint32_t uCID;
1159 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1160 if (RT_SUCCESS(rc))
1161 {
1162 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1163
1164 LogFlowFunc(("uCID=%RU32 -> uEvent=%RU32\n", uCID, uEvent));
1165
1166 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1167 }
1168 break;
1169 }
1170
1171 default:
1172 rc = VERR_NOT_FOUND;
1173 break;
1174 }
1175
1176 if (RT_FAILURE(rc))
1177 {
1178 if (pPayload)
1179 RTMemFree(pPayload);
1180 }
1181 }
1182 else
1183 rc = VERR_NO_MEMORY;
1184 }
1185 }
1186 else
1187 rc = VERR_NO_MEMORY;
1188
1189 if (RT_FAILURE(rc))
1190 {
1191 if (pReply)
1192 RTMemFree(pReply);
1193 }
1194
1195 LogFlowFuncLeaveRC(rc);
1196 return rc;
1197}
1198
1199/**
1200 * transfer client (guest) handler for the Shared Clipboard host service.
1201 *
1202 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1203 * @param pClient Pointer to associated client.
1204 * @param callHandle The client's call handle of this call.
1205 * @param u32Function Function number being called.
1206 * @param cParms Number of function parameters supplied.
1207 * @param paParms Array function parameters supplied.
1208 * @param tsArrival Timestamp of arrival.
1209 */
1210int sharedClipboardSvcTransferHandler(PSHCLCLIENT pClient,
1211 VBOXHGCMCALLHANDLE callHandle,
1212 uint32_t u32Function,
1213 uint32_t cParms,
1214 VBOXHGCMSVCPARM paParms[],
1215 uint64_t tsArrival)
1216{
1217 RT_NOREF(callHandle, paParms, tsArrival);
1218
1219 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1220 pClient->State.uClientID, u32Function, VBoxShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1221
1222#if 0
1223 /* Check if we've the right mode set. */
1224 if (!sharedClipboardSvcTransferMsgIsAllowed(sharedClipboardSvcGetMode(), u32Function))
1225 {
1226 LogFunc(("Wrong clipboard mode, denying access\n"));
1227 return VERR_ACCESS_DENIED;
1228 }
1229#endif
1230
1231 /* A (valid) service extension is needed because VBoxSVC needs to keep track of the
1232 * clipboard areas cached on the host. */
1233 if (!g_ExtState.pfnExtension)
1234 {
1235#ifdef DEBUG_andy
1236 AssertPtr(g_ExtState.pfnExtension);
1237#endif
1238 LogFunc(("Invalid / no service extension set, skipping transfer handling\n"));
1239 return VERR_NOT_SUPPORTED;
1240 }
1241
1242 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1243
1244 /*
1245 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1246 */
1247 uint32_t uCID = 0; /* Context ID */
1248 PSHCLTRANSFER pTransfer = NULL;
1249
1250 switch (u32Function)
1251 {
1252 case VBOX_SHCL_GUEST_FN_STATUS:
1253 break;
1254 default:
1255 {
1256 if (!SharedClipboardTransferCtxGetTotalTransfers(&pClient->TransferCtx))
1257 {
1258 LogFunc(("No transfers found\n"));
1259 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1260 break;
1261 }
1262
1263 if (cParms < 1)
1264 break;
1265
1266 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1267 if (RT_FAILURE(rc))
1268 break;
1269
1270 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1271
1272 pTransfer = SharedClipboardTransferCtxGetTransfer(&pClient->TransferCtx, uTransferID);
1273 if (!pTransfer)
1274 {
1275 LogFunc(("Transfer with ID %RU32 not found\n", uTransferID));
1276 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1277 }
1278 break;
1279 }
1280 }
1281
1282 if (RT_FAILURE(rc))
1283 return rc;
1284
1285 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1286
1287 switch (u32Function)
1288 {
1289#if 0
1290 case VBOX_SHCL_GUEST_FN_STATUS:
1291 {
1292 if (cParms != VBOX_SHCL_CPARMS_STATUS)
1293 break;
1294
1295 SHCLTRANSFERSTATUS uStatus = SHCLTRANSFERSTATUS_NONE;
1296 rc = HGCMSvcGetU32(&paParms[1], &uStatus);
1297 if (RT_FAILURE(rc))
1298 break;
1299
1300 LogFlowFunc(("uStatus: %RU32\n", uStatus));
1301
1302 SharedClipboardTransferCtxTransfersCleanup(&pClient->URI);
1303
1304 if (SharedClipboardTransferCtxTransfersMaximumReached(&pClient->URI))
1305 {
1306 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
1307 break;
1308 }
1309
1310 if (uStatus == SHCLTRANSFERSTATUS_RUNNING)
1311 {
1312 const SHCLTRANSFERDIR enmDir = SHCLTRANSFERDIR_READ;
1313
1314 PSHCLTRANSFER pTransfer;
1315 rc = SharedClipboardTransferCreate(enmDir,
1316 SHCLSOURCE_REMOTE, &pTransfer);
1317 if (RT_SUCCESS(rc))
1318 {
1319 rc = sharedClipboardSvcTransferAreaRegister(&pClient->State, pTransfer);
1320 if (RT_SUCCESS(rc))
1321 {
1322 SHCLPROVIDERCREATIONCTX creationCtx;
1323 RT_ZERO(creationCtx);
1324
1325 creationCtx.enmSource = pClient->State.enmSource;
1326
1327 creationCtx.Interface.pfnTransferOpen = sharedClipboardSvcTransferOpen;
1328 creationCtx.Interface.pfnTransferClose = sharedClipboardSvcTransferClose;
1329 creationCtx.Interface.pfnListOpen = sharedClipboardSvcTransferListOpen;
1330 creationCtx.Interface.pfnListClose = sharedClipboardSvcTransferListClose;
1331 creationCtx.Interface.pfnObjOpen = sharedClipboardSvcTransferObjOpen;
1332 creationCtx.Interface.pfnObjClose = sharedClipboardSvcTransferObjClose;
1333
1334 if (enmDir == SHCLTRANSFERDIR_READ)
1335 {
1336 creationCtx.Interface.pfnRootsGet = sharedClipboardSvcTransferGetRoots;
1337 creationCtx.Interface.pfnListHdrRead = sharedClipboardSvcTransferListHdrRead;
1338 creationCtx.Interface.pfnListEntryRead = sharedClipboardSvcTransferListEntryRead;
1339 creationCtx.Interface.pfnObjRead = sharedClipboardSvcTransferObjRead;
1340 }
1341 else
1342 {
1343 AssertFailed();
1344 }
1345
1346 creationCtx.pvUser = pClient;
1347
1348 /* Register needed callbacks so that we can wait for the meta data to arrive here. */
1349 SHCLTRANSFERCALLBACKS Callbacks;
1350 RT_ZERO(Callbacks);
1351
1352 Callbacks.pvUser = pClient;
1353
1354 Callbacks.pfnTransferPrepare = VBoxSvcClipboardTransferPrepareCallback;
1355 Callbacks.pfnTransferComplete = VBoxSvcClipboardTransferCompleteCallback;
1356 Callbacks.pfnTransferCanceled = VBoxSvcClipboardTransferCanceledCallback;
1357 Callbacks.pfnTransferError = VBoxSvcClipboardTransferErrorCallback;
1358
1359 SharedClipboardTransferSetCallbacks(pTransfer, &Callbacks);
1360
1361 rc = SharedClipboardTransferSetInterface(pTransfer, &creationCtx);
1362 if (RT_SUCCESS(rc))
1363 rc = SharedClipboardTransferCtxTransferAdd(&pClient->URI, pTransfer);
1364 }
1365
1366 if (RT_SUCCESS(rc))
1367 {
1368 rc = SharedClipboardSvcImplTransferCreate(pClient, pTransfer);
1369 if (RT_SUCCESS(rc))
1370 rc = SharedClipboardSvcImplFormatAnnounce(pClient, VBOX_SHCL_FMT_URI_LIST);
1371 }
1372
1373 if (RT_FAILURE(rc))
1374 {
1375 SharedClipboardSvcImplTransferDestroy(pClient, pTransfer);
1376 SharedClipboardTransferDestroy(pTransfer);
1377 }
1378 }
1379 }
1380
1381 LogFlowFunc(("[Client %RU32] VBOX_SHCL_GUEST_FN_STATUS: %Rrc\n", pClient->uClientID, rc));
1382
1383 if (RT_FAILURE(rc))
1384 LogRel(("Shared Clipboard: Initializing transfer failed with %Rrc\n", rc));
1385
1386 break;
1387 }
1388#endif
1389
1390 case VBOX_SHCL_GUEST_FN_REPLY:
1391 {
1392 rc = sharedClipboardSvcTransferHandleReply(pClient, pTransfer, cParms, paParms);
1393 break;
1394 }
1395
1396 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1397 {
1398 break;
1399 }
1400
1401 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1402 {
1403 SHCLROOTLISTHDR lstHdr;
1404 rc = sharedClipboardSvcTransferGetRootListHdr(cParms, paParms, &lstHdr);
1405 if (RT_SUCCESS(rc))
1406 {
1407 void *pvData = SharedClipboardTransferRootListHdrDup(&lstHdr);
1408 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
1409
1410 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1411
1412 PSHCLEVENTPAYLOAD pPayload;
1413 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1414 if (RT_SUCCESS(rc))
1415 {
1416 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1417 if (RT_FAILURE(rc))
1418 SharedClipboardPayloadFree(pPayload);
1419 }
1420 }
1421 break;
1422 }
1423
1424 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1425 {
1426 #if 0
1427 SHCLROOTLISTENTRY lstEntry;
1428 rc = VBoxSvcClipboardGetRootListEntry(cParms, paParms, &lstEntry);
1429 if (RT_SUCCESS(rc))
1430 {
1431 void *pvData = SharedClipboardTransferRootListEntryDup(&lstEntry);
1432 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1433
1434 PSHCLTRANSFERPAYLOAD pPayload;
1435 rc = SharedClipboardTransferPayloadAlloc(SHCLTRANSFEREVENTTYPE_ROOT_LIST_HDR_READ,
1436 pvData, cbData, &pPayload);
1437 if (RT_SUCCESS(rc))
1438 rc = SharedClipboardTransferEventSignal(pTransfer, SHCLTRANSFEREVENTTYPE_ROOT_LIST_HDR_READ,
1439 pPayload);
1440 }
1441 break;
1442 #endif
1443 }
1444
1445 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1446 {
1447 SHCLROOTLISTENTRY lstEntry;
1448 rc = sharedClipboardSvcTransferGetRootListEntry(cParms, paParms, &lstEntry);
1449 if (RT_SUCCESS(rc))
1450 {
1451 void *pvData = SharedClipboardTransferRootListEntryDup(&lstEntry);
1452 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1453
1454 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1455
1456 PSHCLEVENTPAYLOAD pPayload;
1457 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1458 if (RT_SUCCESS(rc))
1459 {
1460 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1461 if (RT_FAILURE(rc))
1462 SharedClipboardPayloadFree(pPayload);
1463 }
1464 }
1465 break;
1466 }
1467
1468 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1469 {
1470 SHCLLISTOPENPARMS listOpenParms;
1471 rc = sharedClipboardSvcTransferGetListOpen(cParms, paParms, &listOpenParms);
1472 if (RT_SUCCESS(rc))
1473 {
1474 SHCLLISTHANDLE hList;
1475 rc = SharedClipboardTransferListOpen(pTransfer, &listOpenParms, &hList);
1476 if (RT_SUCCESS(rc))
1477 {
1478 /* Return list handle. */
1479 HGCMSvcSetU32(&paParms[1], hList);
1480 }
1481 }
1482 break;
1483 }
1484
1485 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1486 {
1487 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1488 break;
1489
1490 SHCLLISTHANDLE hList;
1491 rc = HGCMSvcGetU64(&paParms[1], &hList);
1492 if (RT_SUCCESS(rc))
1493 {
1494 rc = SharedClipboardTransferListClose(pTransfer, hList);
1495 }
1496 break;
1497 }
1498
1499 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1500 {
1501 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1502 break;
1503
1504 SHCLLISTHANDLE hList;
1505 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1506 if (RT_SUCCESS(rc))
1507 {
1508 SHCLLISTHDR hdrList;
1509 rc = SharedClipboardTransferListGetHeader(pTransfer, hList, &hdrList);
1510 /*if (RT_SUCCESS(rc))
1511 rc = sharedClipboardSvcTransferSetListHdr(cParms, paParms, &hdrList);*/
1512 }
1513 break;
1514 }
1515
1516 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1517 {
1518 SHCLLISTHDR hdrList;
1519 rc = SharedClipboardTransferListHdrInit(&hdrList);
1520 if (RT_SUCCESS(rc))
1521 {
1522 SHCLLISTHANDLE hList;
1523 rc = sharedClipboardSvcTransferGetListHdr(cParms, paParms, &hList, &hdrList);
1524 if (RT_SUCCESS(rc))
1525 {
1526 void *pvData = SharedClipboardTransferListHdrDup(&hdrList);
1527 uint32_t cbData = sizeof(SHCLLISTHDR);
1528
1529 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1530
1531 PSHCLEVENTPAYLOAD pPayload;
1532 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1533 if (RT_SUCCESS(rc))
1534 {
1535 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1536 if (RT_FAILURE(rc))
1537 SharedClipboardPayloadFree(pPayload);
1538 }
1539 }
1540 }
1541 break;
1542 }
1543
1544 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1545 {
1546 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1547 break;
1548
1549 SHCLLISTHANDLE hList;
1550 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1551 if (RT_SUCCESS(rc))
1552 {
1553 SHCLLISTENTRY entryList;
1554 rc = SharedClipboardTransferListRead(pTransfer, hList, &entryList);
1555 }
1556 break;
1557 }
1558
1559 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1560 {
1561 SHCLLISTENTRY entryList;
1562 rc = SharedClipboardTransferListEntryInit(&entryList);
1563 if (RT_SUCCESS(rc))
1564 {
1565 SHCLLISTHANDLE hList;
1566 rc = sharedClipboardSvcTransferGetListEntry(cParms, paParms, &hList, &entryList);
1567 if (RT_SUCCESS(rc))
1568 {
1569 void *pvData = SharedClipboardTransferListEntryDup(&entryList);
1570 uint32_t cbData = sizeof(SHCLLISTENTRY);
1571
1572 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1573
1574 PSHCLEVENTPAYLOAD pPayload;
1575 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1576 if (RT_SUCCESS(rc))
1577 {
1578 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1579 if (RT_FAILURE(rc))
1580 SharedClipboardPayloadFree(pPayload);
1581 }
1582 }
1583 }
1584 break;
1585 }
1586
1587 #if 0
1588 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1589 {
1590 break;
1591 }
1592
1593 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1594 {
1595 break;
1596 }
1597
1598 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1599 {
1600 break;
1601 }
1602 #endif
1603
1604 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1605 {
1606 SHCLOBJDATACHUNK dataChunk;
1607 rc = sharedClipboardSvcTransferGetObjDataChunk(cParms, paParms, &dataChunk);
1608 if (RT_SUCCESS(rc))
1609 {
1610 void *pvData = SharedClipboardTransferObjectDataChunkDup(&dataChunk);
1611 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1612
1613 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1614
1615 PSHCLEVENTPAYLOAD pPayload;
1616 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1617 if (RT_SUCCESS(rc))
1618 {
1619 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1620 if (RT_FAILURE(rc))
1621 SharedClipboardPayloadFree(pPayload);
1622 }
1623 }
1624
1625 break;
1626 }
1627
1628 #if 0
1629 case VBOX_SHCL_GUEST_FN_WRITE_DIR:
1630 {
1631 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_DIR\n"));
1632
1633 SHCLDIRDATA dirData;
1634 rc = VBoxSvcClipboardGetDir(cParms, paParms, &dirData);
1635 if (RT_SUCCESS(rc))
1636 {
1637 SharedClipboardArea *pArea = SharedClipboardTransferGetArea(pTransfer);
1638 AssertPtrBreakStmt(pArea, rc = VERR_INVALID_POINTER);
1639
1640 const char *pszCacheDir = pArea->GetDirAbs();
1641 char *pszDir = RTPathJoinA(pszCacheDir, dirData.pszPath);
1642 if (pszDir)
1643 {
1644 LogFlowFunc(("pszDir=%s\n", pszDir));
1645
1646 rc = RTDirCreateFullPath(pszDir, dirData.fMode);
1647 if (RT_SUCCESS(rc))
1648 {
1649 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_DIR, SHCLAREAOBJSTATE_COMPLETE };
1650 int rc2 = pArea->AddObject(pszDir, Obj);
1651 AssertRC(rc2);
1652 }
1653
1654 RTStrFree(pszDir);
1655 }
1656 else
1657 rc = VERR_NO_MEMORY;
1658 }
1659 break;
1660 }
1661
1662 case VBOX_SHCL_GUEST_FN_READ_FILE_HDR:
1663 {
1664 LogFlowFunc(("VBOX_SHCL_GUEST_FN_READ_FILE_HDR\n"));
1665
1666 SHCLFILEHDR fileHdr;
1667 rc = VBoxSvcClipboardSetFileHdr(cParms, paParms, &fileHdr);
1668 break;
1669 }
1670
1671 case VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR:
1672 {
1673 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR\n"));
1674
1675 if (!SharedClipboardTransferObjCtxIsValid(SharedClipboardTransferGetCurrentObjCtx(pTransfer)))
1676 {
1677 pTransfer->State.ObjCtx.pObj = new SharedClipboardTransferObject(SharedClipboardTransferObject::Type_File);
1678 if (pTransfer->State.ObjCtx.pObj) /** @todo Can this throw? */
1679 {
1680 rc = VINF_SUCCESS;
1681 }
1682 else
1683 rc = VERR_NO_MEMORY;
1684 }
1685 else /* There still is another object being processed? */
1686 rc = VERR_WRONG_ORDER;
1687
1688 if (RT_FAILURE(rc))
1689 break;
1690
1691 SHCLFILEHDR fileHdr;
1692 rc = VBoxSvcClipboardGetFileHdr(cParms, paParms, &fileHdr);
1693 if (RT_SUCCESS(rc))
1694 {
1695 SharedClipboardArea *pArea = SharedClipboardTransferGetArea(pTransfer);
1696 AssertPtrBreakStmt(pArea, rc = VERR_WRONG_ORDER);
1697
1698 const char *pszCacheDir = pArea->GetDirAbs();
1699
1700 char pszPathAbs[RTPATH_MAX];
1701 rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszCacheDir, fileHdr.pszFilePath);
1702 if (RT_SUCCESS(rc))
1703 {
1704 rc = SharedClipboardPathSanitize(pszPathAbs, sizeof(pszPathAbs));
1705 if (RT_SUCCESS(rc))
1706 {
1707 PSHCLCLIENTTRANSFEROBJCTX pObjCtx = SharedClipboardTransferGetCurrentObjCtx(pTransfer);
1708 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1709
1710 SharedClipboardTransferObject *pObj = pObjCtx->pObj;
1711 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1712
1713 LogFlowFunc(("pszFile=%s\n", pszPathAbs));
1714
1715 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
1716 rc = pObj->OpenFileEx(pszPathAbs, SharedClipboardTransferObject::View_Target,
1717 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
1718 (fileHdr.fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
1719 if (RT_SUCCESS(rc))
1720 {
1721 rc = pObj->SetSize(fileHdr.cbSize);
1722
1723 /** @todo Unescape path before printing. */
1724 LogRel2(("Clipboard: Transferring guest file '%s' to host (%RU64 bytes, mode 0x%x)\n",
1725 pObj->GetDestPathAbs().c_str(), pObj->GetSize(), pObj->GetMode()));
1726
1727 if (pObj->IsComplete()) /* 0-byte file? We're done already. */
1728 {
1729 /** @todo Sanitize path. */
1730 LogRel2(("Clipboard: Transferring guest file '%s' (0 bytes) to host complete\n",
1731 pObj->GetDestPathAbs().c_str()));
1732
1733 SharedClipboardTransferObjCtxDestroy(&pTransfer->State.ObjCtx);
1734 }
1735
1736 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_FILE, SHCLAREAOBJSTATE_NONE };
1737 int rc2 = pArea->AddObject(pszPathAbs, Obj);
1738 AssertRC(rc2);
1739 }
1740 else
1741 LogRel(("Clipboard: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pszPathAbs, rc));
1742 }
1743 }
1744 }
1745 break;
1746 }
1747
1748 case VBOX_SHCL_GUEST_FN_READ_FILE_DATA:
1749 {
1750 LogFlowFunc(("VBOX_SHCL_FN_READ_FILE_DATA\n"));
1751
1752 SHCLFILEDATA fileData;
1753 rc = VBoxSvcClipboardSetFileData(cParms, paParms, &fileData);
1754 break;
1755 }
1756
1757 case VBOX_SHCL_GUEST_FN_WRITE_FILE_DATA:
1758 {
1759 LogFlowFunc(("VBOX_SHCL_FN_WRITE_FILE_DATA\n"));
1760
1761 if (!SharedClipboardTransferObjCtxIsValid(&pTransfer->State.ObjCtx))
1762 {
1763 rc = VERR_WRONG_ORDER;
1764 break;
1765 }
1766
1767 SHCLFILEDATA fileData;
1768 rc = VBoxSvcClipboardGetFileData(cParms, paParms, &fileData);
1769 if (RT_SUCCESS(rc))
1770 {
1771 PSHCLCLIENTTRANSFEROBJCTX pObjCtx = SharedClipboardTransferGetCurrentObjCtx(pTransfer);
1772 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1773
1774 SharedClipboardTransferObject *pObj = pObjCtx->pObj;
1775 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1776
1777 uint32_t cbWritten;
1778 rc = pObj->Write(fileData.pvData, fileData.cbData, &cbWritten);
1779 if (RT_SUCCESS(rc))
1780 {
1781 Assert(cbWritten <= fileData.cbData);
1782 if (cbWritten < fileData.cbData)
1783 {
1784 /** @todo What to do when the host's disk is full? */
1785 rc = VERR_DISK_FULL;
1786 }
1787
1788 if ( pObj->IsComplete()
1789 || RT_FAILURE(rc))
1790 SharedClipboardTransferObjCtxDestroy(&pTransfer->State.ObjCtx);
1791 }
1792 else
1793 LogRel(("Clipboard: Error writing guest file data for '%s', rc=%Rrc\n", pObj->GetDestPathAbs().c_str(), rc));
1794 }
1795 break;
1796 }
1797#endif
1798 case VBOX_SHCL_GUEST_FN_CANCEL:
1799 {
1800 LogRel2(("Shared Clipboard: Transfer canceled\n"));
1801 break;
1802 }
1803
1804 case VBOX_SHCL_GUEST_FN_ERROR:
1805 {
1806 int rcGuest;
1807 rc = sharedClipboardSvcTransferGetError(cParms,paParms, &rcGuest);
1808 if (RT_SUCCESS(rc))
1809 LogRel(("Shared Clipboard: Transfer error: %Rrc\n", rcGuest));
1810 break;
1811 }
1812
1813 default:
1814 LogFunc(("Not implemented\n"));
1815 break;
1816 }
1817
1818 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
1819 return rc;
1820}
1821
1822/**
1823 * transfer host handler for the Shared Clipboard host service.
1824 *
1825 * @returns VBox status code.
1826 * @param u32Function Function number being called.
1827 * @param cParms Number of function parameters supplied.
1828 * @param paParms Array function parameters supplied.
1829 */
1830int sharedClipboardSvcTransferHostHandler(uint32_t u32Function,
1831 uint32_t cParms,
1832 VBOXHGCMSVCPARM paParms[])
1833{
1834 RT_NOREF(cParms, paParms);
1835
1836 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
1837
1838 switch (u32Function)
1839 {
1840 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
1841 break;
1842
1843 case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
1844 break;
1845
1846 default:
1847 break;
1848
1849 }
1850
1851 LogFlowFuncLeaveRC(rc);
1852 return rc;
1853}
1854
1855/**
1856 * Registers an clipboard transfer area.
1857 *
1858 * @returns VBox status code.
1859 * @param pClientState Client state to use.
1860 * @param pTransfer Shared Clipboard transfer to register a clipboard area for.
1861 */
1862int sharedClipboardSvcTransferAreaRegister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1863{
1864 RT_NOREF(pClientState);
1865
1866 LogFlowFuncEnter();
1867
1868 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is registered for this transfer\n"),
1869 VERR_WRONG_ORDER);
1870
1871 pTransfer->pArea = new SharedClipboardArea();
1872 if (!pTransfer->pArea)
1873 return VERR_NO_MEMORY;
1874
1875 int rc;
1876
1877 if (g_ExtState.pfnExtension)
1878 {
1879 SHCLEXTAREAPARMS parms;
1880 RT_ZERO(parms);
1881
1882 parms.uID = NIL_SHCLAREAID;
1883
1884 /* As the meta data is now complete, register a new clipboard on the host side. */
1885 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
1886 if (RT_SUCCESS(rc))
1887 {
1888 /* Note: Do *not* specify SHCLAREA_OPEN_FLAGS_MUST_NOT_EXIST as flags here, as VBoxSVC took care of the
1889 * clipboard area creation already. */
1890 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */,
1891 SHCLAREA_OPEN_FLAGS_NONE);
1892 }
1893
1894 LogFlowFunc(("Registered new clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1895 parms.uID, pClientState->uClientID, rc));
1896 }
1897 else
1898 rc = VERR_NOT_SUPPORTED;
1899
1900 LogFlowFuncLeaveRC(rc);
1901 return rc;
1902}
1903
1904/**
1905 * Unregisters an clipboard transfer area.
1906 *
1907 * @returns VBox status code.
1908 * @param pClientState Client state to use.
1909 * @param pTransfer Shared Clipboard transfer to unregister a clipboard area from.
1910 */
1911int sharedClipboardSvcTransferAreaUnregister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1912{
1913 RT_NOREF(pClientState);
1914
1915 LogFlowFuncEnter();
1916
1917 if (!pTransfer->pArea)
1918 return VINF_SUCCESS;
1919
1920 int rc = VINF_SUCCESS;
1921
1922 if (g_ExtState.pfnExtension)
1923 {
1924 SHCLEXTAREAPARMS parms;
1925 RT_ZERO(parms);
1926
1927 parms.uID = pTransfer->pArea->GetID();
1928
1929 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
1930 if (RT_SUCCESS(rc))
1931 {
1932 rc = pTransfer->pArea->Close();
1933 if (RT_SUCCESS(rc))
1934 {
1935 delete pTransfer->pArea;
1936 pTransfer->pArea = NULL;
1937 }
1938 }
1939
1940 LogFlowFunc(("Unregistered clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1941 parms.uID, pClientState->uClientID, rc));
1942 }
1943
1944 delete pTransfer->pArea;
1945 pTransfer->pArea = NULL;
1946
1947 LogFlowFuncLeaveRC(rc);
1948 return rc;
1949}
1950
1951/**
1952 * Attaches to an existing (registered) clipboard transfer area.
1953 *
1954 * @returns VBox status code.
1955 * @param pClientState Client state to use.
1956 * @param pTransfer Shared Clipboard transfer to attach a clipboard area to.
1957 * @param uID ID of clipboard area to to attach to. Specify 0 to attach to the most recent one.
1958 */
1959int sharedClipboardSvcTransferAreaAttach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer,
1960 SHCLAREAID uID)
1961{
1962 RT_NOREF(pClientState);
1963
1964 LogFlowFuncEnter();
1965
1966 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is attached to this transfer\n"),
1967 VERR_WRONG_ORDER);
1968
1969 pTransfer->pArea = new SharedClipboardArea();
1970 if (!pTransfer->pArea)
1971 return VERR_NO_MEMORY;
1972
1973 int rc = VINF_SUCCESS;
1974
1975 if (g_ExtState.pfnExtension)
1976 {
1977 SHCLEXTAREAPARMS parms;
1978 RT_ZERO(parms);
1979
1980 parms.uID = uID; /* 0 means most recent clipboard area. */
1981
1982 /* The client now needs to attach to the most recent clipboard area
1983 * to keep a reference to it. The host does the actual book keeping / cleanup then.
1984 *
1985 * This might fail if the host does not have a most recent clipboard area (yet). */
1986 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
1987 if (RT_SUCCESS(rc))
1988 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */);
1989
1990 LogFlowFunc(("Attached client %RU32 to clipboard area %RU32 with rc=%Rrc\n",
1991 pClientState->uClientID, parms.uID, rc));
1992 }
1993 else
1994 rc = VERR_NOT_SUPPORTED;
1995
1996 LogFlowFuncLeaveRC(rc);
1997 return rc;
1998}
1999
2000/**
2001 * Detaches from an clipboard transfer area.
2002 *
2003 * @returns VBox status code.
2004 * @param pClientState Client state to use.
2005 * @param pTransfer Shared Clipboard transfer to detach a clipboard area from.
2006 */
2007int sharedClipboardSvcTransferAreaDetach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
2008{
2009 RT_NOREF(pClientState);
2010
2011 LogFlowFuncEnter();
2012
2013 if (!pTransfer->pArea)
2014 return VINF_SUCCESS;
2015
2016 const uint32_t uAreaID = pTransfer->pArea->GetID();
2017
2018 int rc = VINF_SUCCESS;
2019
2020 if (g_ExtState.pfnExtension)
2021 {
2022 SHCLEXTAREAPARMS parms;
2023 RT_ZERO(parms);
2024 parms.uID = uAreaID;
2025
2026 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
2027
2028 LogFlowFunc(("Detached client %RU32 from clipboard area %RU32 with rc=%Rrc\n",
2029 pClientState->uClientID, uAreaID, rc));
2030 }
2031
2032 delete pTransfer->pArea;
2033 pTransfer->pArea = NULL;
2034
2035 LogFlowFuncLeaveRC(rc);
2036 return rc;
2037}
2038
2039/**
2040 * Reports a transfer status to the guest.
2041 *
2042 * @returns VBox status code.
2043 * @param pClient Client that owns the transfer.
2044 * @param pTransfer Transfer to report status for.
2045 * @param uStatus Status to report.
2046 * @param rcTransfer Result code to report. Optional and depending on status.
2047 * @param puEvent Where to store the created wait event. Optional.
2048 */
2049int sharedClipboardSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
2050 int rcTransfer, PSHCLEVENTID puEvent)
2051{
2052 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2053 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2054 /* puEvent is optional. */
2055
2056 PSHCLCLIENTMSG pMsgReadData = sharedClipboardSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
2057 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
2058 if (!pMsgReadData)
2059 return VERR_NO_MEMORY;
2060
2061 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pTransfer->Events);
2062
2063 HGCMSvcSetU32(&pMsgReadData->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
2064 pTransfer->State.uID, uEvent));
2065 HGCMSvcSetU32(&pMsgReadData->paParms[1], pTransfer->State.enmDir);
2066 HGCMSvcSetU32(&pMsgReadData->paParms[2], uStatus);
2067 HGCMSvcSetU32(&pMsgReadData->paParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
2068 HGCMSvcSetU32(&pMsgReadData->paParms[4], 0 /* fFlags, unused */);
2069
2070 int rc = sharedClipboardSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
2071 if (RT_SUCCESS(rc))
2072 {
2073 rc = SharedClipboardEventRegister(&pTransfer->Events, uEvent);
2074 if (RT_SUCCESS(rc))
2075 {
2076 rc = sharedClipboardSvcClientWakeup(pClient);
2077 if (RT_SUCCESS(rc))
2078 {
2079 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
2080 VBoxShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
2081
2082 if (puEvent)
2083 *puEvent = uEvent;
2084 }
2085 else
2086 SharedClipboardEventUnregister(&pTransfer->Events, uEvent);
2087 }
2088 }
2089
2090 LogFlowFuncLeaveRC(rc);
2091 return rc;
2092}
2093
2094/**
2095 * Starts a new transfer, waiting for acknowledgement by the guest side.
2096 *
2097 * @returns VBox status code.
2098 * @param pClient Client that owns the transfer.
2099 * @param enmDir Transfer direction to start.
2100 * @param enmSource Transfer source to start.
2101 * @param ppTransfer Where to return the created transfer on success. Optional.
2102 */
2103int sharedClipboardSvcTransferStart(PSHCLCLIENT pClient,
2104 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
2105 PSHCLTRANSFER *ppTransfer)
2106{
2107 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2108 /* ppTransfer is optional. */
2109
2110 LogFlowFuncEnter();
2111
2112 SharedClipboardTransferCtxCleanup(&pClient->TransferCtx);
2113
2114 int rc;
2115
2116 if (!SharedClipboardTransferCtxTransfersMaximumReached(&pClient->TransferCtx))
2117 {
2118 LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLTRANSFERDIR_READ ? "read" : "write"));
2119
2120 PSHCLTRANSFER pTransfer;
2121 rc = SharedClipboardTransferCreate(&pTransfer);
2122 if (RT_SUCCESS(rc))
2123 {
2124 SHCLPROVIDERCREATIONCTX creationCtx;
2125 RT_ZERO(creationCtx);
2126
2127 if (enmDir == SHCLTRANSFERDIR_READ)
2128 {
2129 rc = sharedClipboardSvcTransferAreaRegister(&pClient->State, pTransfer);
2130 if (RT_SUCCESS(rc))
2131 {
2132 creationCtx.Interface.pfnTransferOpen = sharedClipboardSvcTransferIfaceOpen;
2133 creationCtx.Interface.pfnTransferClose = sharedClipboardSvcTransferIfaceClose;
2134
2135 creationCtx.Interface.pfnRootsGet = sharedClipboardSvcTransferIfaceGetRoots;
2136
2137 creationCtx.Interface.pfnListOpen = sharedClipboardSvcTransferIfaceListOpen;
2138 creationCtx.Interface.pfnListClose = sharedClipboardSvcTransferIfaceListClose;
2139 creationCtx.Interface.pfnListHdrRead = sharedClipboardSvcTransferIfaceListHdrRead;
2140 creationCtx.Interface.pfnListEntryRead = sharedClipboardSvcTransferIfaceListEntryRead;
2141
2142 creationCtx.Interface.pfnObjOpen = sharedClipboardSvcTransferIfaceObjOpen;
2143 creationCtx.Interface.pfnObjClose = sharedClipboardSvcTransferIfaceObjClose;
2144 creationCtx.Interface.pfnObjRead = sharedClipboardSvcTransferIfaceObjRead;
2145 }
2146 }
2147 else if (enmDir == SHCLTRANSFERDIR_WRITE)
2148 {
2149 creationCtx.Interface.pfnListHdrWrite = sharedClipboardSvcTransferIfaceListHdrWrite;
2150 creationCtx.Interface.pfnListEntryWrite = sharedClipboardSvcTransferIfaceListEntryWrite;
2151 creationCtx.Interface.pfnObjWrite = sharedClipboardSvcTransferIfaceObjWrite;
2152 }
2153 else
2154 AssertFailed();
2155
2156 creationCtx.enmSource = pClient->State.enmSource;
2157 creationCtx.pvUser = pClient;
2158
2159 uint32_t uTransferID = 0;
2160
2161 rc = SharedClipboardTransferSetInterface(pTransfer, &creationCtx);
2162 if (RT_SUCCESS(rc))
2163 {
2164 rc = SharedClipboardSvcImplTransferCreate(pClient, pTransfer);
2165 if (RT_SUCCESS(rc))
2166 {
2167 rc = SharedClipboardTransferCtxTransferRegister(&pClient->TransferCtx, pTransfer, &uTransferID);
2168 if (RT_SUCCESS(rc))
2169 {
2170 rc = SharedClipboardTransferInit(pTransfer, uTransferID, enmDir, enmSource);
2171 if (RT_SUCCESS(rc))
2172 {
2173 SHCLEVENTID uEvent;
2174 rc = sharedClipboardSvcTransferSendStatus(pClient, pTransfer,
2175 SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS,
2176 &uEvent);
2177 if (RT_SUCCESS(rc))
2178 {
2179 LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
2180 pTransfer->State.uID));
2181
2182 PSHCLEVENTPAYLOAD pPayload;
2183 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, &pPayload);
2184 if (RT_SUCCESS(rc))
2185 {
2186 Assert(pPayload->cbData == sizeof(SHCLREPLY));
2187 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
2188 AssertPtr(pReply);
2189
2190 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
2191
2192 if (pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_STARTED)
2193 {
2194 LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
2195 }
2196 else
2197 LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
2198 VBoxShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
2199 pReply->rc, pTransfer->State.uID));
2200 }
2201 else
2202 LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
2203 pTransfer->State.uID, rc));
2204 }
2205 }
2206 }
2207 }
2208 }
2209
2210 if (RT_FAILURE(rc))
2211 {
2212 SharedClipboardTransferCtxTransferUnregister(&pClient->TransferCtx, uTransferID);
2213
2214 SharedClipboardTransferDestroy(pTransfer);
2215
2216 RTMemFree(pTransfer);
2217 pTransfer = NULL;
2218 }
2219 else
2220 {
2221 if (ppTransfer)
2222 *ppTransfer = pTransfer;
2223 }
2224 }
2225
2226 if (RT_FAILURE(rc))
2227 LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
2228 }
2229 else
2230 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2231
2232 LogFlowFuncLeaveRC(rc);
2233 return rc;
2234}
2235
2236/**
2237 * Stops a transfer, communicating the status to the guest side.
2238 *
2239 * @returns VBox status code.
2240 * @param pClient Client that owns the transfer.
2241 * @param pTransfer Transfer to stop.
2242 */
2243int sharedClipboardSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2244{
2245 int rc = SharedClipboardTransferClose(pTransfer);
2246 if (RT_SUCCESS(rc))
2247 {
2248 SHCLEVENTID uEvent;
2249 rc = sharedClipboardSvcTransferSendStatus(pClient, pTransfer,
2250 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS,
2251 &uEvent);
2252 if (RT_SUCCESS(rc))
2253 {
2254 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
2255
2256 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, NULL);
2257 if (RT_SUCCESS(rc))
2258 {
2259 rc = SharedClipboardTransferCtxTransferUnregister(&pClient->TransferCtx, SharedClipboardTransferGetID(pTransfer));
2260
2261 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
2262 }
2263 else
2264 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2265 pTransfer->State.uID, rc));
2266 }
2267 }
2268
2269 LogFlowFuncLeaveRC(rc);
2270 return rc;
2271}
2272
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