VirtualBox

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

Last change on this file since 81078 was 81025, 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: 78.8 KB
Line 
1/* $Id: VBoxSharedClipboardSvc-transfers.cpp 81025 2019-09-26 16:13:25Z 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 shclSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
51 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms);
52static int shclSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
53 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList);
54
55
56/*********************************************************************************************************************************
57* Provider implementation *
58*********************************************************************************************************************************/
59
60DECLCALLBACK(int) shclSvcTransferIfaceOpen(PSHCLPROVIDERCTX pCtx)
61{
62 RT_NOREF(pCtx);
63
64 LogFlowFuncLeave();
65 return VINF_SUCCESS;
66}
67
68DECLCALLBACK(int) shclSvcTransferIfaceClose(PSHCLPROVIDERCTX pCtx)
69{
70 RT_NOREF(pCtx);
71
72 LogFlowFuncLeave();
73 return VINF_SUCCESS;
74}
75
76DECLCALLBACK(int) shclSvcTransferIfaceGetRoots(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 = shclSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ,
86 VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
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 = shclSvcMsgAdd(pClient, pMsgHdr, true /* fAppend */);
96 if (RT_SUCCESS(rc))
97 {
98 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
99 AssertRC(rc2);
100
101 rc = shclSvcClientWakeup(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(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) shclSvcTransferIfaceListOpen(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 = shclSvcMsgAlloc(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 = shclSvcTransferSetListOpen(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, pOpenParms);
214 if (RT_SUCCESS(rc))
215 {
216 rc = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
217 if (RT_SUCCESS(rc))
218 {
219 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
220 AssertRC(rc2);
221
222 rc = shclSvcClientWakeup(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) shclSvcTransferIfaceListClose(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 = shclSvcMsgAlloc(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 = shclSvcTransferSetListClose(pMsg->cParms, pMsg->paParms, &pMsg->Ctx, hList);
272 if (RT_SUCCESS(rc))
273 {
274 rc = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
275 if (RT_SUCCESS(rc))
276 {
277 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
278 AssertRC(rc2);
279
280 rc = shclSvcClientWakeup(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) shclSvcTransferIfaceListHdrRead(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
322 if (RT_SUCCESS(rc))
323 {
324 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
325 AssertRC(rc2);
326
327 rc = shclSvcClientWakeup(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) shclSvcTransferIfaceListHdrWrite(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) shclSvcTransferIfaceListEntryRead(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
383 if (RT_SUCCESS(rc))
384 {
385 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
386 AssertRC(rc2);
387
388 rc = shclSvcClientWakeup(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) shclSvcTransferIfaceListEntryWrite(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 shclSvcTransferIfaceObjOpen(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
449 if (RT_SUCCESS(rc))
450 {
451 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
452 AssertRC(rc2);
453
454 rc = shclSvcClientWakeup(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 shclSvcTransferIfaceObjClose(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
502 if (RT_SUCCESS(rc))
503 {
504 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
505 AssertRC(rc2);
506
507 rc = shclSvcClientWakeup(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 shclSvcTransferIfaceObjRead(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
558 if (RT_SUCCESS(rc))
559 {
560 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
561 AssertRC(rc2);
562
563 rc = shclSvcClientWakeup(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 shclSvcTransferIfaceObjWrite(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 = shclSvcMsgAlloc(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 = shclSvcMsgAdd(pClient, pMsg, true /* fAppend */);
617 if (RT_SUCCESS(rc))
618 {
619 int rc2 = SharedClipboardEventRegister(&pCtx->pTransfer->Events, uEvent);
620 AssertRC(rc2);
621
622 rc = shclSvcClientWakeup(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 * Returns whether a HGCM message is allowed in a certain service mode or not.
655 *
656 * @returns \c true if message is allowed, \c false if not.
657 * @param uMode Service mode to check allowance for.
658 * @param uMsg HGCM message to check allowance for.
659 */
660bool shclSvcTransferMsgIsAllowed(uint32_t uMode, uint32_t uMsg)
661{
662 const bool fHostToGuest = uMode == VBOX_SHCL_MODE_HOST_TO_GUEST
663 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
664
665 const bool fGuestToHost = uMode == VBOX_SHCL_MODE_GUEST_TO_HOST
666 || uMode == VBOX_SHCL_MODE_BIDIRECTIONAL;
667
668 bool fAllowed = false; /* If in doubt, don't allow. */
669
670 switch (uMsg)
671 {
672 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
673 RT_FALL_THROUGH();
674 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
675 RT_FALL_THROUGH();
676 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
677 RT_FALL_THROUGH();
678 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
679 RT_FALL_THROUGH();
680 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
681 fAllowed = fGuestToHost;
682 break;
683
684 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
685 RT_FALL_THROUGH();
686 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
687 RT_FALL_THROUGH();
688 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
689 RT_FALL_THROUGH();
690 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
691 RT_FALL_THROUGH();
692 case VBOX_SHCL_GUEST_FN_OBJ_READ:
693 fAllowed = fHostToGuest;
694 break;
695
696 case VBOX_SHCL_GUEST_FN_CONNECT:
697 RT_FALL_THROUGH();
698 case VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT:
699 RT_FALL_THROUGH();
700 case VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT:
701 RT_FALL_THROUGH();
702 case VBOX_SHCL_GUEST_FN_MSG_GET:
703 RT_FALL_THROUGH();
704 case VBOX_SHCL_GUEST_FN_REPLY:
705 RT_FALL_THROUGH();
706 case VBOX_SHCL_GUEST_FN_CANCEL:
707 RT_FALL_THROUGH();
708 case VBOX_SHCL_GUEST_FN_ERROR:
709 RT_FALL_THROUGH();
710 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
711 RT_FALL_THROUGH();
712 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
713 RT_FALL_THROUGH();
714 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
715 RT_FALL_THROUGH();
716 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
717 fAllowed = fHostToGuest || fGuestToHost;
718 break;
719
720 default:
721 break;
722 }
723
724 LogFlowFunc(("uMsg=%RU32 (%s), uMode=%RU32 -> fAllowed=%RTbool\n", uMsg, VBoxShClGuestMsgToStr(uMsg), uMode, fAllowed));
725 return fAllowed;
726}
727
728/**
729 * Gets a transfer message reply from HGCM service parameters.
730 *
731 * @returns VBox status code.
732 * @param cParms Number of HGCM parameters supplied in \a paParms.
733 * @param paParms Array of HGCM parameters.
734 * @param pReply Where to store the reply.
735 */
736static int shclSvcTransferGetReply(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
737 PSHCLREPLY pReply)
738{
739 int rc;
740
741 if (cParms >= VBOX_SHCL_CPARMS_REPLY_MIN)
742 {
743 uint32_t cbPayload = 0;
744
745 /* paParms[0] has the context ID. */
746 rc = HGCMSvcGetU32(&paParms[1], &pReply->uType);
747 if (RT_SUCCESS(rc))
748 rc = HGCMSvcGetU32(&paParms[2], &pReply->rc);
749 if (RT_SUCCESS(rc))
750 rc = HGCMSvcGetU32(&paParms[3], &cbPayload);
751 if (RT_SUCCESS(rc))
752 {
753 rc = HGCMSvcGetPv(&paParms[4], &pReply->pvPayload, &pReply->cbPayload);
754 AssertReturn(cbPayload == pReply->cbPayload, VERR_INVALID_PARAMETER);
755 }
756
757 if (RT_SUCCESS(rc))
758 {
759 rc = VERR_INVALID_PARAMETER; /* Play safe. */
760
761 switch (pReply->uType)
762 {
763 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
764 {
765 if (cParms >= 6)
766 rc = HGCMSvcGetU32(&paParms[5], &pReply->u.TransferStatus.uStatus);
767 break;
768 }
769
770 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
771 {
772 if (cParms >= 6)
773 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ListOpen.uHandle);
774 break;
775 }
776
777 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
778 {
779 if (cParms >= 6)
780 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjOpen.uHandle);
781 break;
782 }
783
784 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
785 {
786 if (cParms >= 6)
787 rc = HGCMSvcGetU64(&paParms[5], &pReply->u.ObjClose.uHandle);
788 break;
789 }
790
791 default:
792 rc = VERR_NOT_SUPPORTED;
793 break;
794 }
795 }
796 }
797 else
798 rc = VERR_INVALID_PARAMETER;
799
800 LogFlowFuncLeaveRC(rc);
801 return rc;
802}
803
804/**
805 * Gets a transfer root list header from HGCM service parameters.
806 *
807 * @returns VBox status code.
808 * @param cParms Number of HGCM parameters supplied in \a paParms.
809 * @param paParms Array of HGCM parameters.
810 * @param pRootLstHdr Where to store the transfer root list header on success.
811 */
812static int shclSvcTransferGetRootListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
813 PSHCLROOTLISTHDR pRootLstHdr)
814{
815 int rc;
816
817 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE)
818 {
819 rc = HGCMSvcGetU32(&paParms[1], &pRootLstHdr->fRoots);
820 if (RT_SUCCESS(rc))
821 rc = HGCMSvcGetU32(&paParms[2], &pRootLstHdr->cRoots);
822 }
823 else
824 rc = VERR_INVALID_PARAMETER;
825
826 LogFlowFuncLeaveRC(rc);
827 return rc;
828}
829
830/**
831 * Gets a transfer root list entry from HGCM service parameters.
832 *
833 * @returns VBox status code.
834 * @param cParms Number of HGCM parameters supplied in \a paParms.
835 * @param paParms Array of HGCM parameters.
836 * @param pListEntry Where to store the root list entry.
837 */
838static int shclSvcTransferGetRootListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
839 PSHCLROOTLISTENTRY pListEntry)
840{
841 int rc;
842
843 if (cParms == VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE)
844 {
845 rc = HGCMSvcGetU32(&paParms[1], &pListEntry->fInfo);
846 /* Note: paParms[2] contains the entry index, currently being ignored. */
847 if (RT_SUCCESS(rc))
848 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
849 if (RT_SUCCESS(rc))
850 {
851 uint32_t cbInfo;
852 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
853 if (RT_SUCCESS(rc))
854 {
855 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
856 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
857 }
858 }
859 }
860 else
861 rc = VERR_INVALID_PARAMETER;
862
863 LogFlowFuncLeaveRC(rc);
864 return rc;
865}
866
867/**
868 * Gets a transfer list open request from HGCM service parameters.
869 *
870 * @returns VBox status code.
871 * @param cParms Number of HGCM parameters supplied in \a paParms.
872 * @param paParms Array of HGCM parameters.
873 * @param pOpenParms Where to store the open parameters of the request.
874 */
875static int shclSvcTransferGetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
876 PSHCLLISTOPENPARMS pOpenParms)
877{
878 int rc;
879
880 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
881 {
882 uint32_t cbPath = 0;
883 uint32_t cbFilter = 0;
884
885 rc = HGCMSvcGetU32(&paParms[1], &pOpenParms->fList);
886 if (RT_SUCCESS(rc))
887 rc = HGCMSvcGetU32(&paParms[2], &cbPath);
888 if (RT_SUCCESS(rc))
889 {
890 rc = HGCMSvcGetStr(&paParms[3], &pOpenParms->pszPath, &pOpenParms->cbPath);
891 AssertReturn(cbPath == pOpenParms->cbPath, VERR_INVALID_PARAMETER);
892 }
893 if (RT_SUCCESS(rc))
894 rc = HGCMSvcGetU32(&paParms[4], &cbFilter);
895 if (RT_SUCCESS(rc))
896 {
897 rc = HGCMSvcGetStr(&paParms[5], &pOpenParms->pszFilter, &pOpenParms->cbFilter);
898 AssertReturn(cbFilter == pOpenParms->cbFilter, VERR_INVALID_PARAMETER);
899 }
900
901 if (RT_SUCCESS(rc))
902 {
903 /** @todo Some more validation. */
904 }
905 }
906 else
907 rc = VERR_INVALID_PARAMETER;
908
909 LogFlowFuncLeaveRC(rc);
910 return rc;
911}
912
913/**
914 * Sets a transfer list open request to HGCM service parameters.
915 *
916 * @returns VBox status code.
917 * @param cParms Number of HGCM parameters supplied in \a paParms.
918 * @param paParms Array of HGCM parameters.
919 * @param pMsgCtx Message context to use.
920 * @param pOpenParms List open parameters to set.
921 */
922static int shclSvcTransferSetListOpen(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
923 PSHCLMSGCTX pMsgCtx, PSHCLLISTOPENPARMS pOpenParms)
924{
925 int rc;
926
927 if (cParms == VBOX_SHCL_CPARMS_LIST_OPEN)
928 {
929 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
930 HGCMSvcSetU32(&paParms[1], pOpenParms->fList);
931 HGCMSvcSetU32(&paParms[2], pOpenParms->cbFilter);
932 HGCMSvcSetPv (&paParms[3], pOpenParms->pszFilter, pOpenParms->cbFilter);
933 HGCMSvcSetU32(&paParms[4], pOpenParms->cbPath);
934 HGCMSvcSetPv (&paParms[5], pOpenParms->pszPath, pOpenParms->cbPath);
935 HGCMSvcSetU64(&paParms[6], 0); /* OUT: uHandle */
936
937 rc = VINF_SUCCESS;
938 }
939 else
940 rc = VERR_INVALID_PARAMETER;
941
942 LogFlowFuncLeaveRC(rc);
943 return rc;
944}
945
946/**
947 * Sets a transfer list close request to HGCM service parameters.
948 *
949 * @returns VBox status code.
950 * @param cParms Number of HGCM parameters supplied in \a paParms.
951 * @param paParms Array of HGCM parameters.
952 * @param pMsgCtx Message context to use.
953 * @param hList Handle of list to close.
954 */
955static int shclSvcTransferSetListClose(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
956 PSHCLMSGCTX pMsgCtx, SHCLLISTHANDLE hList)
957{
958 int rc;
959
960 if (cParms == VBOX_SHCL_CPARMS_LIST_CLOSE)
961 {
962 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
963 HGCMSvcSetU64(&paParms[1], hList);
964
965 rc = VINF_SUCCESS;
966 }
967 else
968 rc = VERR_INVALID_PARAMETER;
969
970 LogFlowFuncLeaveRC(rc);
971 return rc;
972}
973
974/**
975 * Gets a transfer list header from HGCM service parameters.
976 *
977 * @returns VBox status code.
978 * @param cParms Number of HGCM parameters supplied in \a paParms.
979 * @param paParms Array of HGCM parameters.
980 * @param phList Where to store the list handle.
981 * @param pListHdr Where to store the list header.
982 */
983static int shclSvcTransferGetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
984 PSHCLLISTHANDLE phList, PSHCLLISTHDR pListHdr)
985{
986 int rc;
987
988 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
989 {
990 rc = HGCMSvcGetU64(&paParms[1], phList);
991 /* Note: Flags (paParms[2]) not used here. */
992 if (RT_SUCCESS(rc))
993 rc = HGCMSvcGetU32(&paParms[3], &pListHdr->fFeatures);
994 if (RT_SUCCESS(rc))
995 rc = HGCMSvcGetU64(&paParms[4], &pListHdr->cTotalObjects);
996 if (RT_SUCCESS(rc))
997 rc = HGCMSvcGetU64(&paParms[5], &pListHdr->cbTotalSize);
998
999 if (RT_SUCCESS(rc))
1000 {
1001 /** @todo Validate pvMetaFmt + cbMetaFmt. */
1002 /** @todo Validate header checksum. */
1003 }
1004 }
1005 else
1006 rc = VERR_INVALID_PARAMETER;
1007
1008 LogFlowFuncLeaveRC(rc);
1009 return rc;
1010}
1011
1012#if 0
1013/**
1014 * Sets a transfer list header to HGCM service parameters.
1015 *
1016 * @returns VBox status code.
1017 * @param cParms Number of HGCM parameters supplied in \a paParms.
1018 * @param paParms Array of HGCM parameters.
1019 * @param pMsgCtx Message context to use.
1020 * @param pListHdr Pointer to data to set to the HGCM parameters.
1021 */
1022static int shclSvcTransferSetListHdr(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1023 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTHDR pListHdr)
1024{
1025 int rc;
1026
1027 if (cParms == VBOX_SHCL_CPARMS_LIST_HDR)
1028 {
1029 /** @todo Set pvMetaFmt + cbMetaFmt. */
1030 /** @todo Calculate header checksum. */
1031
1032 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
1033 HGCMSvcSetU32(&paParms[1], pListHdr->fFeatures);
1034 HGCMSvcSetU32(&paParms[2], 0 /* Features, will be returned on success */);
1035 HGCMSvcSetU64(&paParms[3], pListHdr->cTotalObjects);
1036 HGCMSvcSetU64(&paParms[4], pListHdr->cbTotalSize);
1037
1038 rc = VINF_SUCCESS;
1039 }
1040 else
1041 rc = VERR_INVALID_PARAMETER;
1042
1043 LogFlowFuncLeaveRC(rc);
1044 return rc;
1045}
1046#endif
1047
1048/**
1049 * Gets a transfer list entry from HGCM service parameters.
1050 *
1051 * @returns VBox status code.
1052 * @param cParms Number of HGCM parameters supplied in \a paParms.
1053 * @param paParms Array of HGCM parameters.
1054 * @param phList Where to store the list handle.
1055 * @param pListEntry Where to store the list entry.
1056 */
1057static int shclSvcTransferGetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1058 PSHCLLISTHANDLE phList, PSHCLLISTENTRY pListEntry)
1059{
1060 int rc;
1061
1062 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1063 {
1064 rc = HGCMSvcGetU64(&paParms[1], phList);
1065 if (RT_SUCCESS(rc))
1066 rc = HGCMSvcGetU32(&paParms[2], &pListEntry->fInfo);
1067 if (RT_SUCCESS(rc))
1068 rc = HGCMSvcGetPv(&paParms[3], (void **)&pListEntry->pszName, &pListEntry->cbName);
1069 if (RT_SUCCESS(rc))
1070 {
1071 uint32_t cbInfo;
1072 rc = HGCMSvcGetU32(&paParms[4], &cbInfo);
1073 if (RT_SUCCESS(rc))
1074 {
1075 rc = HGCMSvcGetPv(&paParms[5], &pListEntry->pvInfo, &pListEntry->cbInfo);
1076 AssertReturn(cbInfo == pListEntry->cbInfo, VERR_INVALID_PARAMETER);
1077 }
1078 }
1079
1080 if (RT_SUCCESS(rc))
1081 {
1082 if (!SharedClipboardTransferListEntryIsValid(pListEntry))
1083 rc = VERR_INVALID_PARAMETER;
1084 }
1085 }
1086 else
1087 rc = VERR_INVALID_PARAMETER;
1088
1089 LogFlowFuncLeaveRC(rc);
1090 return rc;
1091}
1092
1093#if 0
1094/**
1095 * Sets a transfer data chunk to HGCM service parameters.
1096 *
1097 * @returns VBox status code.
1098 * @param cParms Number of HGCM parameters supplied in \a paParms.
1099 * @param paParms Array of HGCM parameters.
1100 * @param pMsgCtx Message context to use.
1101 * @param pListEntry Pointer to data to set to the HGCM parameters.
1102 */
1103static int shclSvcTransferSetListEntry(uint32_t cParms, VBOXHGCMSVCPARM paParms[],
1104 PVBOXSHCLMSGCTX pMsgCtx, PSHCLLISTENTRY pListEntry)
1105{
1106 int rc;
1107
1108 if (cParms == VBOX_SHCL_CPARMS_LIST_ENTRY)
1109 {
1110 /** @todo Calculate chunk checksum. */
1111
1112 HGCMSvcSetU32(&paParms[0], pMsgCtx->uContextID);
1113 HGCMSvcSetU32(&paParms[1], pListEntry->fInfo);
1114 HGCMSvcSetU32(&paParms[2], pListEntry->cbInfo);
1115 HGCMSvcSetPv (&paParms[3], pListEntry->pvInfo, pListEntry->cbInfo);
1116
1117 rc = VINF_SUCCESS;
1118 }
1119 else
1120 rc = VERR_INVALID_PARAMETER;
1121
1122 LogFlowFuncLeaveRC(rc);
1123 return rc;
1124}
1125#endif
1126
1127/**
1128 * Gets a transfer object data chunk from HGCM service parameters.
1129 *
1130 * @returns VBox status code.
1131 * @param cParms Number of HGCM parameters supplied in \a paParms.
1132 * @param paParms Array of HGCM parameters.
1133 * @param pDataChunk Where to store the object data chunk data.
1134 */
1135static int shclSvcTransferGetObjDataChunk(uint32_t cParms, VBOXHGCMSVCPARM paParms[], PSHCLOBJDATACHUNK pDataChunk)
1136{
1137 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1138 AssertPtrReturn(pDataChunk, VERR_INVALID_PARAMETER);
1139
1140 int rc;
1141
1142 if (cParms == VBOX_SHCL_CPARMS_OBJ_WRITE)
1143 {
1144 rc = HGCMSvcGetU64(&paParms[1], &pDataChunk->uHandle);
1145 if (RT_SUCCESS(rc))
1146 {
1147 uint32_t cbData;
1148 rc = HGCMSvcGetU32(&paParms[2], &cbData);
1149 if (RT_SUCCESS(rc))
1150 {
1151 rc = HGCMSvcGetPv(&paParms[3], &pDataChunk->pvData, &pDataChunk->cbData);
1152 AssertReturn(cbData == pDataChunk->cbData, VERR_INVALID_PARAMETER);
1153
1154 /** @todo Implement checksum handling. */
1155 }
1156 }
1157 }
1158 else
1159 rc = VERR_INVALID_PARAMETER;
1160
1161 LogFlowFuncLeaveRC(rc);
1162 return rc;
1163}
1164
1165/**
1166 * Gets a transfer error from HGCM service parameters.
1167 *
1168 * @returns VBox status code.
1169 * @param cParms Number of HGCM parameters supplied in \a paParms.
1170 * @param paParms Array of HGCM parameters.
1171 * @param pRc Where to store the received error code.
1172 */
1173static int shclSvcTransferGetError(uint32_t cParms, VBOXHGCMSVCPARM paParms[], int *pRc)
1174{
1175 AssertPtrReturn(paParms, VERR_INVALID_PARAMETER);
1176 AssertPtrReturn(pRc, VERR_INVALID_PARAMETER);
1177
1178 int rc;
1179
1180 if (cParms == VBOX_SHCL_CPARMS_ERROR)
1181 {
1182 rc = HGCMSvcGetU32(&paParms[1], (uint32_t *)pRc); /** @todo int vs. uint32_t !!! */
1183 }
1184 else
1185 rc = VERR_INVALID_PARAMETER;
1186
1187 LogFlowFuncLeaveRC(rc);
1188 return rc;
1189}
1190
1191/**
1192 * Handles a guest reply (VBOX_SHCL_GUEST_FN_REPLY) message.
1193 *
1194 * @returns VBox status code.
1195 * @param pClient Pointer to associated client.
1196 * @param pTransfer Pointer to transfer to handle guest reply for.
1197 * @param cParms Number of function parameters supplied.
1198 * @param paParms Array function parameters supplied.
1199 */
1200static int shclSvcTransferHandleReply(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer,
1201 uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1202{
1203 RT_NOREF(pClient);
1204
1205 int rc;
1206
1207 uint32_t cbReply = sizeof(SHCLREPLY);
1208 PSHCLREPLY pReply = (PSHCLREPLY)RTMemAlloc(cbReply);
1209 if (pReply)
1210 {
1211 rc = shclSvcTransferGetReply(cParms, paParms, pReply);
1212 if (RT_SUCCESS(rc))
1213 {
1214 PSHCLEVENTPAYLOAD pPayload
1215 = (PSHCLEVENTPAYLOAD)RTMemAlloc(sizeof(SHCLEVENTPAYLOAD));
1216 if (pPayload)
1217 {
1218 pPayload->pvData = pReply;
1219 pPayload->cbData = cbReply;
1220
1221 switch (pReply->uType)
1222 {
1223 case VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS:
1224 RT_FALL_THROUGH();
1225 case VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN:
1226 RT_FALL_THROUGH();
1227 case VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE:
1228 RT_FALL_THROUGH();
1229 case VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN:
1230 RT_FALL_THROUGH();
1231 case VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE:
1232 {
1233 uint32_t uCID;
1234 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1235 if (RT_SUCCESS(rc))
1236 {
1237 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1238
1239 LogFlowFunc(("uCID=%RU32 -> uEvent=%RU32\n", uCID, uEvent));
1240
1241 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1242 }
1243 break;
1244 }
1245
1246 default:
1247 rc = VERR_NOT_FOUND;
1248 break;
1249 }
1250
1251 if (RT_FAILURE(rc))
1252 {
1253 if (pPayload)
1254 RTMemFree(pPayload);
1255 }
1256 }
1257 else
1258 rc = VERR_NO_MEMORY;
1259 }
1260 }
1261 else
1262 rc = VERR_NO_MEMORY;
1263
1264 if (RT_FAILURE(rc))
1265 {
1266 if (pReply)
1267 RTMemFree(pReply);
1268 }
1269
1270 LogFlowFuncLeaveRC(rc);
1271 return rc;
1272}
1273
1274/**
1275 * transfer client (guest) handler for the Shared Clipboard host service.
1276 *
1277 * @returns VBox status code, or VINF_HGCM_ASYNC_EXECUTE if returning to the client will be deferred.
1278 * @param pClient Pointer to associated client.
1279 * @param callHandle The client's call handle of this call.
1280 * @param u32Function Function number being called.
1281 * @param cParms Number of function parameters supplied.
1282 * @param paParms Array function parameters supplied.
1283 * @param tsArrival Timestamp of arrival.
1284 */
1285int shclSvcTransferHandler(PSHCLCLIENT pClient,
1286 VBOXHGCMCALLHANDLE callHandle,
1287 uint32_t u32Function,
1288 uint32_t cParms,
1289 VBOXHGCMSVCPARM paParms[],
1290 uint64_t tsArrival)
1291{
1292 RT_NOREF(callHandle, paParms, tsArrival);
1293
1294 LogFlowFunc(("uClient=%RU32, u32Function=%RU32 (%s), cParms=%RU32, g_ExtState.pfnExtension=%p\n",
1295 pClient->State.uClientID, u32Function, VBoxShClGuestMsgToStr(u32Function), cParms, g_ExtState.pfnExtension));
1296
1297 /* Check if we've the right mode set. */
1298 if (!shclSvcTransferMsgIsAllowed(shclSvcGetMode(), u32Function))
1299 {
1300 LogFunc(("Wrong clipboard mode, denying access\n"));
1301 return VERR_ACCESS_DENIED;
1302 }
1303
1304 /* A (valid) service extension is needed because VBoxSVC needs to keep track of the
1305 * clipboard areas cached on the host. */
1306 if (!g_ExtState.pfnExtension)
1307 {
1308#ifdef DEBUG_andy
1309 AssertPtr(g_ExtState.pfnExtension);
1310#endif
1311 LogFunc(("Invalid / no service extension set, skipping transfer handling\n"));
1312 return VERR_NOT_SUPPORTED;
1313 }
1314
1315 int rc = VERR_INVALID_PARAMETER; /* Play safe by default. */
1316
1317 /*
1318 * Pre-check: For certain messages we need to make sure that a (right) transfer is present.
1319 */
1320 uint32_t uCID = 0; /* Context ID */
1321 PSHCLTRANSFER pTransfer = NULL;
1322
1323 switch (u32Function)
1324 {
1325 default:
1326 {
1327 if (!SharedClipboardTransferCtxGetTotalTransfers(&pClient->TransferCtx))
1328 {
1329 LogFunc(("No transfers found\n"));
1330 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1331 break;
1332 }
1333
1334 if (cParms < 1)
1335 break;
1336
1337 rc = HGCMSvcGetU32(&paParms[0], &uCID);
1338 if (RT_FAILURE(rc))
1339 break;
1340
1341 const SHCLTRANSFERID uTransferID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(uCID);
1342
1343 pTransfer = SharedClipboardTransferCtxGetTransfer(&pClient->TransferCtx, uTransferID);
1344 if (!pTransfer)
1345 {
1346 LogFunc(("Transfer with ID %RU32 not found\n", uTransferID));
1347 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
1348 }
1349 break;
1350 }
1351 }
1352
1353 if (RT_FAILURE(rc))
1354 return rc;
1355
1356 rc = VERR_INVALID_PARAMETER; /* Play safe. */
1357
1358 switch (u32Function)
1359 {
1360 case VBOX_SHCL_GUEST_FN_REPLY:
1361 {
1362 rc = shclSvcTransferHandleReply(pClient, pTransfer, cParms, paParms);
1363 break;
1364 }
1365
1366 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ:
1367 {
1368 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ)
1369 break;
1370
1371 SHCLROOTLISTHDR rootListHdr;
1372 RT_ZERO(rootListHdr);
1373
1374 rootListHdr.cRoots = SharedClipboardTransferRootsCount(pTransfer);
1375
1376 HGCMSvcSetU32(&paParms[0], 0 /* Context ID */);
1377 HGCMSvcSetU32(&paParms[1], rootListHdr.fRoots);
1378 HGCMSvcSetU32(&paParms[2], rootListHdr.cRoots);
1379
1380 rc = VINF_SUCCESS;
1381 break;
1382 }
1383
1384 case VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE:
1385 {
1386 SHCLROOTLISTHDR lstHdr;
1387 rc = shclSvcTransferGetRootListHdr(cParms, paParms, &lstHdr);
1388 if (RT_SUCCESS(rc))
1389 {
1390 void *pvData = SharedClipboardTransferRootListHdrDup(&lstHdr);
1391 uint32_t cbData = sizeof(SHCLROOTLISTHDR);
1392
1393 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1394
1395 PSHCLEVENTPAYLOAD pPayload;
1396 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1397 if (RT_SUCCESS(rc))
1398 {
1399 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1400 if (RT_FAILURE(rc))
1401 SharedClipboardPayloadFree(pPayload);
1402 }
1403 }
1404 break;
1405 }
1406
1407 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ:
1408 {
1409 if (cParms != VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ)
1410 break;
1411
1412 /* paParms[1] contains fInfo flags, currently unused. */
1413 uint32_t uIndex;
1414 rc = HGCMSvcGetU32(&paParms[2], &uIndex);
1415 if (RT_SUCCESS(rc))
1416 {
1417 SHCLROOTLISTENTRY rootListEntry;
1418 rc = SharedClipboardTransferRootsEntry(pTransfer, uIndex, &rootListEntry);
1419 if (RT_SUCCESS(rc))
1420 {
1421 HGCMSvcSetPv (&paParms[3], rootListEntry.pszName, rootListEntry.cbName);
1422 HGCMSvcSetU32(&paParms[4], rootListEntry.cbName);
1423 HGCMSvcSetPv (&paParms[5], rootListEntry.pvInfo, rootListEntry.cbInfo);
1424 }
1425 }
1426 break;
1427 }
1428
1429 case VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE:
1430 {
1431 SHCLROOTLISTENTRY lstEntry;
1432 rc = shclSvcTransferGetRootListEntry(cParms, paParms, &lstEntry);
1433 if (RT_SUCCESS(rc))
1434 {
1435 void *pvData = SharedClipboardTransferRootListEntryDup(&lstEntry);
1436 uint32_t cbData = sizeof(SHCLROOTLISTENTRY);
1437
1438 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1439
1440 PSHCLEVENTPAYLOAD pPayload;
1441 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1442 if (RT_SUCCESS(rc))
1443 {
1444 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1445 if (RT_FAILURE(rc))
1446 SharedClipboardPayloadFree(pPayload);
1447 }
1448 }
1449 break;
1450 }
1451
1452 case VBOX_SHCL_GUEST_FN_LIST_OPEN:
1453 {
1454 SHCLLISTOPENPARMS listOpenParms;
1455 rc = shclSvcTransferGetListOpen(cParms, paParms, &listOpenParms);
1456 if (RT_SUCCESS(rc))
1457 {
1458 SHCLLISTHANDLE hList;
1459 rc = SharedClipboardTransferListOpen(pTransfer, &listOpenParms, &hList);
1460 if (RT_SUCCESS(rc))
1461 {
1462 /* Return list handle. */
1463 HGCMSvcSetU32(&paParms[1], hList);
1464 }
1465 }
1466 break;
1467 }
1468
1469 case VBOX_SHCL_GUEST_FN_LIST_CLOSE:
1470 {
1471 if (cParms != VBOX_SHCL_CPARMS_LIST_CLOSE)
1472 break;
1473
1474 SHCLLISTHANDLE hList;
1475 rc = HGCMSvcGetU64(&paParms[1], &hList);
1476 if (RT_SUCCESS(rc))
1477 {
1478 rc = SharedClipboardTransferListClose(pTransfer, hList);
1479 }
1480 break;
1481 }
1482
1483 case VBOX_SHCL_GUEST_FN_LIST_HDR_READ:
1484 {
1485 if (cParms != VBOX_SHCL_CPARMS_LIST_HDR)
1486 break;
1487
1488 SHCLLISTHANDLE hList;
1489 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1490 if (RT_SUCCESS(rc))
1491 {
1492 SHCLLISTHDR hdrList;
1493 rc = SharedClipboardTransferListGetHeader(pTransfer, hList, &hdrList);
1494 /*if (RT_SUCCESS(rc))
1495 rc = shclSvcTransferSetListHdr(cParms, paParms, &hdrList);*/
1496 }
1497 break;
1498 }
1499
1500 case VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE:
1501 {
1502 SHCLLISTHDR hdrList;
1503 rc = SharedClipboardTransferListHdrInit(&hdrList);
1504 if (RT_SUCCESS(rc))
1505 {
1506 SHCLLISTHANDLE hList;
1507 rc = shclSvcTransferGetListHdr(cParms, paParms, &hList, &hdrList);
1508 if (RT_SUCCESS(rc))
1509 {
1510 void *pvData = SharedClipboardTransferListHdrDup(&hdrList);
1511 uint32_t cbData = sizeof(SHCLLISTHDR);
1512
1513 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1514
1515 PSHCLEVENTPAYLOAD pPayload;
1516 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1517 if (RT_SUCCESS(rc))
1518 {
1519 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1520 if (RT_FAILURE(rc))
1521 SharedClipboardPayloadFree(pPayload);
1522 }
1523 }
1524 }
1525 break;
1526 }
1527
1528 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ:
1529 {
1530 if (cParms != VBOX_SHCL_CPARMS_LIST_ENTRY)
1531 break;
1532
1533 SHCLLISTHANDLE hList;
1534 rc = HGCMSvcGetU64(&paParms[1], &hList); /* Get list handle. */
1535 if (RT_SUCCESS(rc))
1536 {
1537 SHCLLISTENTRY entryList;
1538 rc = SharedClipboardTransferListRead(pTransfer, hList, &entryList);
1539 }
1540 break;
1541 }
1542
1543 case VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE:
1544 {
1545 SHCLLISTENTRY entryList;
1546 rc = SharedClipboardTransferListEntryInit(&entryList);
1547 if (RT_SUCCESS(rc))
1548 {
1549 SHCLLISTHANDLE hList;
1550 rc = shclSvcTransferGetListEntry(cParms, paParms, &hList, &entryList);
1551 if (RT_SUCCESS(rc))
1552 {
1553 void *pvData = SharedClipboardTransferListEntryDup(&entryList);
1554 uint32_t cbData = sizeof(SHCLLISTENTRY);
1555
1556 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1557
1558 PSHCLEVENTPAYLOAD pPayload;
1559 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1560 if (RT_SUCCESS(rc))
1561 {
1562 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1563 if (RT_FAILURE(rc))
1564 SharedClipboardPayloadFree(pPayload);
1565 }
1566 }
1567 }
1568 break;
1569 }
1570
1571 #if 0
1572 case VBOX_SHCL_GUEST_FN_OBJ_OPEN:
1573 {
1574 break;
1575 }
1576
1577 case VBOX_SHCL_GUEST_FN_OBJ_CLOSE:
1578 {
1579 break;
1580 }
1581
1582 case VBOX_SHCL_GUEST_FN_OBJ_READ:
1583 {
1584 break;
1585 }
1586 #endif
1587
1588 case VBOX_SHCL_GUEST_FN_OBJ_WRITE:
1589 {
1590 SHCLOBJDATACHUNK dataChunk;
1591 rc = shclSvcTransferGetObjDataChunk(cParms, paParms, &dataChunk);
1592 if (RT_SUCCESS(rc))
1593 {
1594 void *pvData = SharedClipboardTransferObjectDataChunkDup(&dataChunk);
1595 uint32_t cbData = sizeof(SHCLOBJDATACHUNK);
1596
1597 const SHCLEVENTID uEvent = VBOX_SHCL_CONTEXTID_GET_EVENT(uCID);
1598
1599 PSHCLEVENTPAYLOAD pPayload;
1600 rc = SharedClipboardPayloadAlloc(uEvent, pvData, cbData, &pPayload);
1601 if (RT_SUCCESS(rc))
1602 {
1603 rc = SharedClipboardEventSignal(&pTransfer->Events, uEvent, pPayload);
1604 if (RT_FAILURE(rc))
1605 SharedClipboardPayloadFree(pPayload);
1606 }
1607 }
1608
1609 break;
1610 }
1611
1612 #if 0
1613 case VBOX_SHCL_GUEST_FN_WRITE_DIR:
1614 {
1615 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_DIR\n"));
1616
1617 SHCLDIRDATA dirData;
1618 rc = VBoxSvcClipboardGetDir(cParms, paParms, &dirData);
1619 if (RT_SUCCESS(rc))
1620 {
1621 SharedClipboardArea *pArea = SharedClipboardTransferGetArea(pTransfer);
1622 AssertPtrBreakStmt(pArea, rc = VERR_INVALID_POINTER);
1623
1624 const char *pszCacheDir = pArea->GetDirAbs();
1625 char *pszDir = RTPathJoinA(pszCacheDir, dirData.pszPath);
1626 if (pszDir)
1627 {
1628 LogFlowFunc(("pszDir=%s\n", pszDir));
1629
1630 rc = RTDirCreateFullPath(pszDir, dirData.fMode);
1631 if (RT_SUCCESS(rc))
1632 {
1633 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_DIR, SHCLAREAOBJSTATE_COMPLETE };
1634 int rc2 = pArea->AddObject(pszDir, Obj);
1635 AssertRC(rc2);
1636 }
1637
1638 RTStrFree(pszDir);
1639 }
1640 else
1641 rc = VERR_NO_MEMORY;
1642 }
1643 break;
1644 }
1645
1646 case VBOX_SHCL_GUEST_FN_READ_FILE_HDR:
1647 {
1648 LogFlowFunc(("VBOX_SHCL_GUEST_FN_READ_FILE_HDR\n"));
1649
1650 SHCLFILEHDR fileHdr;
1651 rc = VBoxSvcClipboardSetFileHdr(cParms, paParms, &fileHdr);
1652 break;
1653 }
1654
1655 case VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR:
1656 {
1657 LogFlowFunc(("VBOX_SHCL_GUEST_FN_WRITE_FILE_HDR\n"));
1658
1659 if (!SharedClipboardTransferObjCtxIsValid(SharedClipboardTransferGetCurrentObjCtx(pTransfer)))
1660 {
1661 pTransfer->State.ObjCtx.pObj = new SharedClipboardTransferObject(SharedClipboardTransferObject::Type_File);
1662 if (pTransfer->State.ObjCtx.pObj) /** @todo Can this throw? */
1663 {
1664 rc = VINF_SUCCESS;
1665 }
1666 else
1667 rc = VERR_NO_MEMORY;
1668 }
1669 else /* There still is another object being processed? */
1670 rc = VERR_WRONG_ORDER;
1671
1672 if (RT_FAILURE(rc))
1673 break;
1674
1675 SHCLFILEHDR fileHdr;
1676 rc = VBoxSvcClipboardGetFileHdr(cParms, paParms, &fileHdr);
1677 if (RT_SUCCESS(rc))
1678 {
1679 SharedClipboardArea *pArea = SharedClipboardTransferGetArea(pTransfer);
1680 AssertPtrBreakStmt(pArea, rc = VERR_WRONG_ORDER);
1681
1682 const char *pszCacheDir = pArea->GetDirAbs();
1683
1684 char pszPathAbs[RTPATH_MAX];
1685 rc = RTPathJoin(pszPathAbs, sizeof(pszPathAbs), pszCacheDir, fileHdr.pszFilePath);
1686 if (RT_SUCCESS(rc))
1687 {
1688 rc = SharedClipboardPathSanitize(pszPathAbs, sizeof(pszPathAbs));
1689 if (RT_SUCCESS(rc))
1690 {
1691 PSHCLCLIENTTRANSFEROBJCTX pObjCtx = SharedClipboardTransferGetCurrentObjCtx(pTransfer);
1692 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1693
1694 SharedClipboardTransferObject *pObj = pObjCtx->pObj;
1695 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1696
1697 LogFlowFunc(("pszFile=%s\n", pszPathAbs));
1698
1699 /** @todo Add sparse file support based on fFlags? (Use Open(..., fFlags | SPARSE). */
1700 rc = pObj->OpenFileEx(pszPathAbs, SharedClipboardTransferObject::View_Target,
1701 RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE,
1702 (fileHdr.fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR);
1703 if (RT_SUCCESS(rc))
1704 {
1705 rc = pObj->SetSize(fileHdr.cbSize);
1706
1707 /** @todo Unescape path before printing. */
1708 LogRel2(("Clipboard: Transferring guest file '%s' to host (%RU64 bytes, mode 0x%x)\n",
1709 pObj->GetDestPathAbs().c_str(), pObj->GetSize(), pObj->GetMode()));
1710
1711 if (pObj->IsComplete()) /* 0-byte file? We're done already. */
1712 {
1713 /** @todo Sanitize path. */
1714 LogRel2(("Clipboard: Transferring guest file '%s' (0 bytes) to host complete\n",
1715 pObj->GetDestPathAbs().c_str()));
1716
1717 SharedClipboardTransferObjCtxDestroy(&pTransfer->State.ObjCtx);
1718 }
1719
1720 SHCLAREAOBJ Obj = { SHCLAREAOBJTYPE_FILE, SHCLAREAOBJSTATE_NONE };
1721 int rc2 = pArea->AddObject(pszPathAbs, Obj);
1722 AssertRC(rc2);
1723 }
1724 else
1725 LogRel(("Clipboard: Error opening/creating guest file '%s' on host, rc=%Rrc\n", pszPathAbs, rc));
1726 }
1727 }
1728 }
1729 break;
1730 }
1731
1732 case VBOX_SHCL_GUEST_FN_READ_FILE_DATA:
1733 {
1734 LogFlowFunc(("VBOX_SHCL_FN_READ_FILE_DATA\n"));
1735
1736 SHCLFILEDATA fileData;
1737 rc = VBoxSvcClipboardSetFileData(cParms, paParms, &fileData);
1738 break;
1739 }
1740
1741 case VBOX_SHCL_GUEST_FN_WRITE_FILE_DATA:
1742 {
1743 LogFlowFunc(("VBOX_SHCL_FN_WRITE_FILE_DATA\n"));
1744
1745 if (!SharedClipboardTransferObjCtxIsValid(&pTransfer->State.ObjCtx))
1746 {
1747 rc = VERR_WRONG_ORDER;
1748 break;
1749 }
1750
1751 SHCLFILEDATA fileData;
1752 rc = VBoxSvcClipboardGetFileData(cParms, paParms, &fileData);
1753 if (RT_SUCCESS(rc))
1754 {
1755 PSHCLCLIENTTRANSFEROBJCTX pObjCtx = SharedClipboardTransferGetCurrentObjCtx(pTransfer);
1756 AssertPtrBreakStmt(pObjCtx, VERR_INVALID_POINTER);
1757
1758 SharedClipboardTransferObject *pObj = pObjCtx->pObj;
1759 AssertPtrBreakStmt(pObj, VERR_INVALID_POINTER);
1760
1761 uint32_t cbWritten;
1762 rc = pObj->Write(fileData.pvData, fileData.cbData, &cbWritten);
1763 if (RT_SUCCESS(rc))
1764 {
1765 Assert(cbWritten <= fileData.cbData);
1766 if (cbWritten < fileData.cbData)
1767 {
1768 /** @todo What to do when the host's disk is full? */
1769 rc = VERR_DISK_FULL;
1770 }
1771
1772 if ( pObj->IsComplete()
1773 || RT_FAILURE(rc))
1774 SharedClipboardTransferObjCtxDestroy(&pTransfer->State.ObjCtx);
1775 }
1776 else
1777 LogRel(("Clipboard: Error writing guest file data for '%s', rc=%Rrc\n", pObj->GetDestPathAbs().c_str(), rc));
1778 }
1779 break;
1780 }
1781#endif
1782 case VBOX_SHCL_GUEST_FN_CANCEL:
1783 {
1784 LogRel2(("Shared Clipboard: Transfer canceled\n"));
1785 break;
1786 }
1787
1788 case VBOX_SHCL_GUEST_FN_ERROR:
1789 {
1790 int rcGuest;
1791 rc = shclSvcTransferGetError(cParms,paParms, &rcGuest);
1792 if (RT_SUCCESS(rc))
1793 LogRel(("Shared Clipboard: Transfer error: %Rrc\n", rcGuest));
1794 break;
1795 }
1796
1797 default:
1798 LogFunc(("Not implemented\n"));
1799 break;
1800 }
1801
1802 LogFlowFunc(("[Client %RU32] Returning rc=%Rrc\n", pClient->State.uClientID, rc));
1803 return rc;
1804}
1805
1806/**
1807 * Transfer host handler for the Shared Clipboard host service.
1808 *
1809 * @returns VBox status code.
1810 * @param u32Function Function number being called.
1811 * @param cParms Number of function parameters supplied.
1812 * @param paParms Array function parameters supplied.
1813 */
1814int shclSvcTransferHostHandler(uint32_t u32Function,
1815 uint32_t cParms,
1816 VBOXHGCMSVCPARM paParms[])
1817{
1818 RT_NOREF(cParms, paParms);
1819
1820 int rc = VERR_NOT_IMPLEMENTED; /* Play safe. */
1821
1822 switch (u32Function)
1823 {
1824 case VBOX_SHCL_HOST_FN_CANCEL: /** @todo Implement this. */
1825 break;
1826
1827 case VBOX_SHCL_HOST_FN_ERROR: /** @todo Implement this. */
1828 break;
1829
1830 default:
1831 break;
1832
1833 }
1834
1835 LogFlowFuncLeaveRC(rc);
1836 return rc;
1837}
1838
1839/**
1840 * Registers an clipboard transfer area.
1841 *
1842 * @returns VBox status code.
1843 * @param pClientState Client state to use.
1844 * @param pTransfer Shared Clipboard transfer to register a clipboard area for.
1845 */
1846int shclSvcTransferAreaRegister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1847{
1848 RT_NOREF(pClientState);
1849
1850 LogFlowFuncEnter();
1851
1852 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is registered for this transfer\n"),
1853 VERR_WRONG_ORDER);
1854
1855 pTransfer->pArea = new SharedClipboardArea();
1856 if (!pTransfer->pArea)
1857 return VERR_NO_MEMORY;
1858
1859 int rc;
1860
1861 if (g_ExtState.pfnExtension)
1862 {
1863 SHCLEXTAREAPARMS parms;
1864 RT_ZERO(parms);
1865
1866 parms.uID = NIL_SHCLAREAID;
1867
1868 /* As the meta data is now complete, register a new clipboard on the host side. */
1869 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_REGISTER, &parms, sizeof(parms));
1870 if (RT_SUCCESS(rc))
1871 {
1872 /* Note: Do *not* specify SHCLAREA_OPEN_FLAGS_MUST_NOT_EXIST as flags here, as VBoxSVC took care of the
1873 * clipboard area creation already. */
1874 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */,
1875 SHCLAREA_OPEN_FLAGS_NONE);
1876 }
1877
1878 LogFlowFunc(("Registered new clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1879 parms.uID, pClientState->uClientID, rc));
1880 }
1881 else
1882 rc = VERR_NOT_SUPPORTED;
1883
1884 LogFlowFuncLeaveRC(rc);
1885 return rc;
1886}
1887
1888/**
1889 * Unregisters an clipboard transfer area.
1890 *
1891 * @returns VBox status code.
1892 * @param pClientState Client state to use.
1893 * @param pTransfer Shared Clipboard transfer to unregister a clipboard area from.
1894 */
1895int shclSvcTransferAreaUnregister(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1896{
1897 RT_NOREF(pClientState);
1898
1899 LogFlowFuncEnter();
1900
1901 if (!pTransfer->pArea)
1902 return VINF_SUCCESS;
1903
1904 int rc = VINF_SUCCESS;
1905
1906 if (g_ExtState.pfnExtension)
1907 {
1908 SHCLEXTAREAPARMS parms;
1909 RT_ZERO(parms);
1910
1911 parms.uID = pTransfer->pArea->GetID();
1912
1913 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_UNREGISTER, &parms, sizeof(parms));
1914 if (RT_SUCCESS(rc))
1915 {
1916 rc = pTransfer->pArea->Close();
1917 if (RT_SUCCESS(rc))
1918 {
1919 delete pTransfer->pArea;
1920 pTransfer->pArea = NULL;
1921 }
1922 }
1923
1924 LogFlowFunc(("Unregistered clipboard area (%RU32) by client %RU32 with rc=%Rrc\n",
1925 parms.uID, pClientState->uClientID, rc));
1926 }
1927
1928 delete pTransfer->pArea;
1929 pTransfer->pArea = NULL;
1930
1931 LogFlowFuncLeaveRC(rc);
1932 return rc;
1933}
1934
1935/**
1936 * Attaches to an existing (registered) clipboard transfer area.
1937 *
1938 * @returns VBox status code.
1939 * @param pClientState Client state to use.
1940 * @param pTransfer Shared Clipboard transfer to attach a clipboard area to.
1941 * @param uID ID of clipboard area to to attach to. Specify 0 to attach to the most recent one.
1942 */
1943int shclSvcTransferAreaAttach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer,
1944 SHCLAREAID uID)
1945{
1946 RT_NOREF(pClientState);
1947
1948 LogFlowFuncEnter();
1949
1950 AssertMsgReturn(pTransfer->pArea == NULL, ("An area already is attached to this transfer\n"),
1951 VERR_WRONG_ORDER);
1952
1953 pTransfer->pArea = new SharedClipboardArea();
1954 if (!pTransfer->pArea)
1955 return VERR_NO_MEMORY;
1956
1957 int rc = VINF_SUCCESS;
1958
1959 if (g_ExtState.pfnExtension)
1960 {
1961 SHCLEXTAREAPARMS parms;
1962 RT_ZERO(parms);
1963
1964 parms.uID = uID; /* 0 means most recent clipboard area. */
1965
1966 /* The client now needs to attach to the most recent clipboard area
1967 * to keep a reference to it. The host does the actual book keeping / cleanup then.
1968 *
1969 * This might fail if the host does not have a most recent clipboard area (yet). */
1970 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_ATTACH, &parms, sizeof(parms));
1971 if (RT_SUCCESS(rc))
1972 rc = pTransfer->pArea->OpenTemp(parms.uID /* Area ID */);
1973
1974 LogFlowFunc(("Attached client %RU32 to clipboard area %RU32 with rc=%Rrc\n",
1975 pClientState->uClientID, parms.uID, rc));
1976 }
1977 else
1978 rc = VERR_NOT_SUPPORTED;
1979
1980 LogFlowFuncLeaveRC(rc);
1981 return rc;
1982}
1983
1984/**
1985 * Detaches from an clipboard transfer area.
1986 *
1987 * @returns VBox status code.
1988 * @param pClientState Client state to use.
1989 * @param pTransfer Shared Clipboard transfer to detach a clipboard area from.
1990 */
1991int shclSvcTransferAreaDetach(PSHCLCLIENTSTATE pClientState, PSHCLTRANSFER pTransfer)
1992{
1993 RT_NOREF(pClientState);
1994
1995 LogFlowFuncEnter();
1996
1997 if (!pTransfer->pArea)
1998 return VINF_SUCCESS;
1999
2000 const uint32_t uAreaID = pTransfer->pArea->GetID();
2001
2002 int rc = VINF_SUCCESS;
2003
2004 if (g_ExtState.pfnExtension)
2005 {
2006 SHCLEXTAREAPARMS parms;
2007 RT_ZERO(parms);
2008 parms.uID = uAreaID;
2009
2010 rc = g_ExtState.pfnExtension(g_ExtState.pvExtension, VBOX_CLIPBOARD_EXT_FN_AREA_DETACH, &parms, sizeof(parms));
2011
2012 LogFlowFunc(("Detached client %RU32 from clipboard area %RU32 with rc=%Rrc\n",
2013 pClientState->uClientID, uAreaID, rc));
2014 }
2015
2016 delete pTransfer->pArea;
2017 pTransfer->pArea = NULL;
2018
2019 LogFlowFuncLeaveRC(rc);
2020 return rc;
2021}
2022
2023/**
2024 * Reports a transfer status to the guest.
2025 *
2026 * @returns VBox status code.
2027 * @param pClient Client that owns the transfer.
2028 * @param pTransfer Transfer to report status for.
2029 * @param uStatus Status to report.
2030 * @param rcTransfer Result code to report. Optional and depending on status.
2031 * @param puEvent Where to store the created wait event. Optional.
2032 */
2033int shclSvcTransferSendStatus(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus,
2034 int rcTransfer, PSHCLEVENTID puEvent)
2035{
2036 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2037 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
2038 /* puEvent is optional. */
2039
2040 PSHCLCLIENTMSG pMsgReadData = shclSvcMsgAlloc(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS,
2041 VBOX_SHCL_CPARMS_TRANSFER_STATUS);
2042 if (!pMsgReadData)
2043 return VERR_NO_MEMORY;
2044
2045 const SHCLEVENTID uEvent = SharedClipboardEventIDGenerate(&pTransfer->Events);
2046
2047 HGCMSvcSetU32(&pMsgReadData->paParms[0], VBOX_SHCL_CONTEXTID_MAKE(pClient->State.uSessionID,
2048 pTransfer->State.uID, uEvent));
2049 HGCMSvcSetU32(&pMsgReadData->paParms[1], pTransfer->State.enmDir);
2050 HGCMSvcSetU32(&pMsgReadData->paParms[2], uStatus);
2051 HGCMSvcSetU32(&pMsgReadData->paParms[3], (uint32_t)rcTransfer); /** @todo uint32_t vs. int. */
2052 HGCMSvcSetU32(&pMsgReadData->paParms[4], 0 /* fFlags, unused */);
2053
2054 int rc = shclSvcMsgAdd(pClient, pMsgReadData, true /* fAppend */);
2055 if (RT_SUCCESS(rc))
2056 {
2057 rc = SharedClipboardEventRegister(&pTransfer->Events, uEvent);
2058 if (RT_SUCCESS(rc))
2059 {
2060 rc = shclSvcClientWakeup(pClient);
2061 if (RT_SUCCESS(rc))
2062 {
2063 LogRel2(("Shared Clipboard: Reported status %s (rc=%Rrc) of transfer %RU32 to guest\n",
2064 VBoxShClTransferStatusToStr(uStatus), rcTransfer, pTransfer->State.uID));
2065
2066 if (puEvent)
2067 *puEvent = uEvent;
2068 }
2069 else
2070 SharedClipboardEventUnregister(&pTransfer->Events, uEvent);
2071 }
2072 }
2073
2074 LogFlowFuncLeaveRC(rc);
2075 return rc;
2076}
2077
2078/**
2079 * Starts a new transfer, waiting for acknowledgement by the guest side.
2080 *
2081 * @returns VBox status code.
2082 * @param pClient Client that owns the transfer.
2083 * @param enmDir Transfer direction to start.
2084 * @param enmSource Transfer source to start.
2085 * @param ppTransfer Where to return the created transfer on success. Optional.
2086 */
2087int shclSvcTransferStart(PSHCLCLIENT pClient,
2088 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource,
2089 PSHCLTRANSFER *ppTransfer)
2090{
2091 AssertPtrReturn(pClient, VERR_INVALID_POINTER);
2092 /* ppTransfer is optional. */
2093
2094 LogFlowFuncEnter();
2095
2096 SharedClipboardTransferCtxCleanup(&pClient->TransferCtx);
2097
2098 int rc;
2099
2100 if (!SharedClipboardTransferCtxTransfersMaximumReached(&pClient->TransferCtx))
2101 {
2102 LogRel2(("Shared Clipboard: Starting %s transfer ...\n", enmDir == SHCLTRANSFERDIR_READ ? "read" : "write"));
2103
2104 PSHCLTRANSFER pTransfer;
2105 rc = SharedClipboardTransferCreate(&pTransfer);
2106 if (RT_SUCCESS(rc))
2107 {
2108 SHCLPROVIDERCREATIONCTX creationCtx;
2109 RT_ZERO(creationCtx);
2110
2111 if (enmDir == SHCLTRANSFERDIR_READ)
2112 {
2113 rc = shclSvcTransferAreaRegister(&pClient->State, pTransfer);
2114 if (RT_SUCCESS(rc))
2115 {
2116 creationCtx.Interface.pfnTransferOpen = shclSvcTransferIfaceOpen;
2117 creationCtx.Interface.pfnTransferClose = shclSvcTransferIfaceClose;
2118
2119 creationCtx.Interface.pfnRootsGet = shclSvcTransferIfaceGetRoots;
2120
2121 creationCtx.Interface.pfnListOpen = shclSvcTransferIfaceListOpen;
2122 creationCtx.Interface.pfnListClose = shclSvcTransferIfaceListClose;
2123 creationCtx.Interface.pfnListHdrRead = shclSvcTransferIfaceListHdrRead;
2124 creationCtx.Interface.pfnListEntryRead = shclSvcTransferIfaceListEntryRead;
2125
2126 creationCtx.Interface.pfnObjOpen = shclSvcTransferIfaceObjOpen;
2127 creationCtx.Interface.pfnObjClose = shclSvcTransferIfaceObjClose;
2128 creationCtx.Interface.pfnObjRead = shclSvcTransferIfaceObjRead;
2129 }
2130 }
2131 else if (enmDir == SHCLTRANSFERDIR_WRITE)
2132 {
2133 creationCtx.Interface.pfnListHdrWrite = shclSvcTransferIfaceListHdrWrite;
2134 creationCtx.Interface.pfnListEntryWrite = shclSvcTransferIfaceListEntryWrite;
2135 creationCtx.Interface.pfnObjWrite = shclSvcTransferIfaceObjWrite;
2136 }
2137 else
2138 AssertFailed();
2139
2140 creationCtx.enmSource = pClient->State.enmSource;
2141 creationCtx.pvUser = pClient;
2142
2143 uint32_t uTransferID = 0;
2144
2145 rc = SharedClipboardTransferSetInterface(pTransfer, &creationCtx);
2146 if (RT_SUCCESS(rc))
2147 {
2148 rc = ShClSvcImplTransferCreate(pClient, pTransfer);
2149 if (RT_SUCCESS(rc))
2150 {
2151 rc = SharedClipboardTransferCtxTransferRegister(&pClient->TransferCtx, pTransfer, &uTransferID);
2152 if (RT_SUCCESS(rc))
2153 {
2154 rc = SharedClipboardTransferInit(pTransfer, uTransferID, enmDir, enmSource);
2155 if (RT_SUCCESS(rc))
2156 {
2157 SHCLEVENTID uEvent;
2158 rc = shclSvcTransferSendStatus(pClient, pTransfer,
2159 SHCLTRANSFERSTATUS_INITIALIZED, VINF_SUCCESS,
2160 &uEvent);
2161 if (RT_SUCCESS(rc))
2162 {
2163 LogRel2(("Shared Clipboard: Waiting for start of transfer %RU32 on guest ...\n",
2164 pTransfer->State.uID));
2165
2166 PSHCLEVENTPAYLOAD pPayload;
2167 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, &pPayload);
2168 if (RT_SUCCESS(rc))
2169 {
2170 Assert(pPayload->cbData == sizeof(SHCLREPLY));
2171 PSHCLREPLY pReply = (PSHCLREPLY)pPayload->pvData;
2172 AssertPtr(pReply);
2173
2174 Assert(pReply->uType == VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS);
2175
2176 if (pReply->u.TransferStatus.uStatus == SHCLTRANSFERSTATUS_STARTED)
2177 {
2178 LogRel2(("Shared Clipboard: Started transfer %RU32 on guest\n", pTransfer->State.uID));
2179 }
2180 else
2181 LogRel(("Shared Clipboard: Guest reported status %s (error %Rrc) while starting transfer %RU32\n",
2182 VBoxShClTransferStatusToStr(pReply->u.TransferStatus.uStatus),
2183 pReply->rc, pTransfer->State.uID));
2184 }
2185 else
2186 LogRel(("Shared Clipboard: Unable to start transfer %RU32 on guest, rc=%Rrc\n",
2187 pTransfer->State.uID, rc));
2188 }
2189 }
2190 }
2191 }
2192 }
2193
2194 if (RT_FAILURE(rc))
2195 {
2196 SharedClipboardTransferCtxTransferUnregister(&pClient->TransferCtx, uTransferID);
2197
2198 SharedClipboardTransferDestroy(pTransfer);
2199
2200 RTMemFree(pTransfer);
2201 pTransfer = NULL;
2202 }
2203 else
2204 {
2205 if (ppTransfer)
2206 *ppTransfer = pTransfer;
2207 }
2208 }
2209
2210 if (RT_FAILURE(rc))
2211 LogRel(("Shared Clipboard: Starting transfer failed with %Rrc\n", rc));
2212 }
2213 else
2214 rc = VERR_SHCLPB_MAX_TRANSFERS_REACHED;
2215
2216 LogFlowFuncLeaveRC(rc);
2217 return rc;
2218}
2219
2220/**
2221 * Stops a transfer, communicating the status to the guest side.
2222 *
2223 * @returns VBox status code.
2224 * @param pClient Client that owns the transfer.
2225 * @param pTransfer Transfer to stop.
2226 */
2227int shclSvcTransferStop(PSHCLCLIENT pClient, PSHCLTRANSFER pTransfer)
2228{
2229 int rc = SharedClipboardTransferClose(pTransfer);
2230 if (RT_SUCCESS(rc))
2231 {
2232 SHCLEVENTID uEvent;
2233 rc = shclSvcTransferSendStatus(pClient, pTransfer,
2234 SHCLTRANSFERSTATUS_STOPPED, VINF_SUCCESS,
2235 &uEvent);
2236 if (RT_SUCCESS(rc))
2237 {
2238 LogRel2(("Shared Clipboard: Waiting for stop of transfer %RU32 on guest ...\n", pTransfer->State.uID));
2239
2240 rc = SharedClipboardEventWait(&pTransfer->Events, uEvent, pTransfer->uTimeoutMs, NULL);
2241 if (RT_SUCCESS(rc))
2242 {
2243 rc = SharedClipboardTransferCtxTransferUnregister(&pClient->TransferCtx, SharedClipboardTransferGetID(pTransfer));
2244
2245 LogRel2(("Shared Clipboard: Stopped transfer %RU32 on guest\n", pTransfer->State.uID));
2246 }
2247 else
2248 LogRel(("Shared Clipboard: Unable to stop transfer %RU32 on guest, rc=%Rrc\n",
2249 pTransfer->State.uID, rc));
2250 }
2251 }
2252
2253 LogFlowFuncLeaveRC(rc);
2254 return rc;
2255}
2256
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