VirtualBox

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

Last change on this file since 100367 was 100367, checked in by vboxsync, 23 months ago

Shared Clipboard: More work on making the internal APIs more fine grained and easier to follow. bugref:9437

  • Property svn:eol-style set to native
  • Property svn:keyword set to Id
  • Property svn:keywords set to Author Date Id Revision
File size: 106.1 KB
Line 
1/* $Id: VBoxGuestR3LibClipboard.cpp 100367 2023-07-04 16:23:18Z vboxsync $ */
2/** @file
3 * VBoxGuestR3Lib - Ring-3 Support Library for VirtualBox guest additions, Shared Clipboard.
4 */
5
6/*
7 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.215389.xyz.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include <VBox/GuestHost/SharedClipboard.h>
42#include <VBox/GuestHost/clipboard-helper.h>
43#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
44# include <VBox/GuestHost/SharedClipboard-transfers.h>
45#endif
46#include <VBox/HostServices/VBoxClipboardSvc.h>
47#include <VBox/err.h>
48#include <iprt/assert.h>
49#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
50# include <iprt/dir.h>
51# include <iprt/file.h>
52# include <iprt/path.h>
53#endif
54#include <iprt/string.h>
55#include <iprt/cpp/ministring.h>
56
57#ifdef LOG_GROUP
58 #undef LOG_GROUP
59#endif
60#define LOG_GROUP LOG_GROUP_SHARED_CLIPBOARD
61#include <VBox/log.h>
62
63#include "VBoxGuestR3LibInternal.h"
64
65
66/*
67 * Function naming convention:
68 *
69 * FunctionNameRecv = Receives a host message (request).
70 * FunctionNameReply = Replies to a host message (request).
71 * FunctionNameSend = Sends a guest message to the host.
72 */
73
74
75/*********************************************************************************************************************************
76* Prototypes *
77*********************************************************************************************************************************/
78
79
80/**
81 * Connects to the Shared Clipboard service, legacy version, do not use anymore.
82 *
83 * @returns VBox status code
84 * @param pidClient Where to put the client id on success. The client id
85 * must be passed to all the other clipboard calls.
86 */
87VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient)
88{
89 int rc = VbglR3HGCMConnect("VBoxSharedClipboard", pidClient);
90 if (RT_FAILURE(rc))
91 {
92 if (rc == VERR_HGCM_SERVICE_NOT_FOUND)
93 LogRel(("Shared Clipboard: Unabled to connect, as host service was not found, skipping\n"));
94 else
95 LogRel(("Shared Clipboard: Unabled to connect to host service, rc=%Rrc\n", rc));
96 }
97 LogFlowFuncLeaveRC(rc);
98 return rc;
99}
100
101
102/**
103 * Connects to the Shared Clipboard service, extended version.
104 *
105 * @returns VBox status code.
106 * @param pCtx Command context. This will be initialized by this
107 * call.
108 * @param fGuestFeatures The guest features supported by this client,
109 * VBOX_SHCL_GF_0_XXX.
110 */
111VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures)
112{
113 /*
114 * Intialize the context structure.
115 */
116 pCtx->idClient = 0;
117 pCtx->fGuestFeatures = fGuestFeatures;
118 pCtx->fHostFeatures = 0;
119 pCtx->fUseLegacyProtocol = true;
120 pCtx->idContext = 0;
121
122#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
123 /* Init callback table. */
124 RT_ZERO(pCtx->Transfers.Callbacks);
125 /* Indicate that this guest supports Shared Clipboard file transfers. */
126 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS;
127# ifdef RT_OS_WINDOWS
128 /* Indicate that on Windows guest OSes we have our own IDataObject implementation which
129 * integrates nicely into the guest's Windows Explorer showing / handling the Shared Clipboard file transfers. */
130 pCtx->fGuestFeatures |= VBOX_SHCL_GF_0_TRANSFERS_FRONTEND;
131# endif
132 pCtx->Transfers.cbChunkSize = VBOX_SHCL_DEFAULT_CHUNK_SIZE; /** @todo Make this configurable. */
133 pCtx->Transfers.cbMaxChunkSize = VBOX_SHCL_MAX_CHUNK_SIZE; /** @todo Ditto. */
134#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
135
136 /*
137 * First step is connecting to the HGCM service.
138 */
139 int rc = VbglR3ClipboardConnect(&pCtx->idClient);
140 if (RT_SUCCESS(rc))
141 {
142 /*
143 * Next is reporting our features. If this fails, assume older host.
144 */
145 rc = VbglR3ClipboardReportFeatures(pCtx->idClient, pCtx->fGuestFeatures, &pCtx->fHostFeatures);
146 if (RT_SUCCESS(rc))
147 {
148 LogRel2(("Shared Clipboard: Guest features: %#RX64 - Host features: %#RX64\n",
149 pCtx->fGuestFeatures, pCtx->fHostFeatures));
150
151 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID)
152 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_CONTEXT_ID) )
153 {
154 pCtx->fUseLegacyProtocol = false;
155
156#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
157 if ( (pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS)
158 && (pCtx->fGuestFeatures & VBOX_SHCL_GF_0_TRANSFERS) )
159 {
160 VBoxShClParmNegotiateChunkSize MsgChunkSize;
161 do
162 {
163 VBGL_HGCM_HDR_INIT(&MsgChunkSize.hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE,
164 VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE);
165 MsgChunkSize.cb32MaxChunkSize.SetUInt32(pCtx->Transfers.cbMaxChunkSize);
166 MsgChunkSize.cb32ChunkSize.SetUInt32(0); /* If set to 0, let the host choose. */
167 rc = VbglR3HGCMCall(&MsgChunkSize.hdr, sizeof(MsgChunkSize));
168 } while (rc == VERR_INTERRUPTED);
169 if (RT_SUCCESS(rc))
170 {
171 Assert(MsgChunkSize.cb32ChunkSize.type == VMMDevHGCMParmType_32bit);
172 pCtx->Transfers.cbChunkSize = RT_MIN(MsgChunkSize.cb32ChunkSize.u.value32, pCtx->Transfers.cbChunkSize);
173 Assert(MsgChunkSize.cb32MaxChunkSize.type == VMMDevHGCMParmType_32bit);
174 pCtx->Transfers.cbMaxChunkSize = RT_MIN(MsgChunkSize.cb32MaxChunkSize.u.value32, pCtx->Transfers.cbMaxChunkSize);
175
176 LogRel2(("Shared Clipboard: Using chunk size %RU32 (maximum is %RU32)\n",
177 pCtx->Transfers.cbChunkSize, pCtx->Transfers.cbMaxChunkSize));
178 }
179 }
180 else
181 {
182 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_TRANSFERS))
183 LogRel(("Shared Clipboard: Host does not support transfers\n"));
184 }
185#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
186 }
187 else
188 {
189 if (!(pCtx->fHostFeatures & VBOX_SHCL_HF_0_CONTEXT_ID))
190 LogRel(("Shared Clipboard: Host does not support context IDs, using legacy protocol\n"));
191
192 pCtx->fUseLegacyProtocol = true;
193 }
194 }
195 else
196 {
197 AssertLogRelMsg(rc == VERR_NOT_SUPPORTED || rc == VERR_NOT_IMPLEMENTED,
198 ("Reporting features failed: %Rrc\n", rc));
199 pCtx->fUseLegacyProtocol = true;
200 }
201 }
202
203 LogFlowFuncLeaveRC(rc);
204 return rc;
205}
206
207
208/**
209 * Reports features to the host and retrieve host feature set.
210 *
211 * @returns VBox status code.
212 * @param idClient The client ID returned by VbglR3ClipboardConnect().
213 * @param fGuestFeatures Features to report, VBOX_SHCL_GF_XXX.
214 * @param pfHostFeatures Where to store the features VBOX_SHCL_HF_XXX.
215 */
216VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures)
217{
218 int rc;
219 do
220 {
221 struct
222 {
223 VBGLIOCHGCMCALL Hdr;
224 HGCMFunctionParameter f64Features0;
225 HGCMFunctionParameter f64Features1;
226 } Msg;
227 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FEATURES, 2);
228 VbglHGCMParmUInt64Set(&Msg.f64Features0, fGuestFeatures);
229 VbglHGCMParmUInt64Set(&Msg.f64Features1, VBOX_SHCL_GF_1_MUST_BE_ONE);
230
231 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
232 if (RT_SUCCESS(rc))
233 {
234 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
235 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
236 if (Msg.f64Features1.u.value64 & VBOX_SHCL_GF_1_MUST_BE_ONE)
237 rc = VERR_NOT_SUPPORTED;
238 else if (pfHostFeatures)
239 *pfHostFeatures = Msg.f64Features0.u.value64;
240 break;
241 }
242 } while (rc == VERR_INTERRUPTED);
243 return rc;
244
245}
246
247
248/**
249 * Disconnects from the Shared Clipboard service, legacy version, do not use anymore.
250 *
251 * @returns VBox status code.
252 * @param idClient The client id returned by VbglR3ClipboardConnect().
253 */
254VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient)
255{
256 return VbglR3HGCMDisconnect(idClient);
257}
258
259
260/**
261 * Disconnects from the Shared Clipboard service, extended version.
262 *
263 * @returns VBox status code.
264 * @param pCtx Shared Clipboard command context to use for the connection.
265 */
266VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx)
267{
268 int rc = VbglR3ClipboardDisconnect(pCtx->idClient);
269 if (RT_SUCCESS(rc))
270 {
271 pCtx->idClient = 0;
272 }
273
274 LogFlowFuncLeaveRC(rc);
275 return rc;
276}
277
278
279/**
280 * Receives reported formats from the host.
281 *
282 * @returns VBox status code.
283 * @param pCtx Shared Clipboard command context to use for the
284 * connection.
285 * @param pfFormats Where to store the received formats from the host.
286 */
287static int vbglR3ClipboardFormatsReportRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMATS pfFormats)
288{
289 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
290 AssertPtrReturn(pfFormats, VERR_INVALID_POINTER);
291
292 *pfFormats = 0;
293
294 struct
295 {
296 VBGLIOCHGCMCALL Hdr;
297 HGCMFunctionParameter id64Context;
298 HGCMFunctionParameter f32Formats;
299 } Msg;
300
301 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
302 Msg.id64Context.SetUInt32(VBOX_SHCL_HOST_MSG_FORMATS_REPORT);
303 Msg.f32Formats.SetUInt32(0);
304
305 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
306 if (RT_SUCCESS(rc))
307 {
308 rc = Msg.f32Formats.GetUInt32(pfFormats);
309 AssertRC(rc);
310 }
311
312 LogFlowFuncLeaveRC(rc);
313 return rc;
314}
315
316
317/**
318 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA_CID message.
319 *
320 * @returns VBox status code.
321 * @param pCtx Shared Clipboard command context to use for the connection.
322 * @param pfFormat Where to return the requested format.
323 */
324static int vbglR3ClipboardFetchReadDataCid(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
325{
326 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
327 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
328
329 struct
330 {
331 VBGLIOCHGCMCALL Hdr;
332 HGCMFunctionParameter id64Context;
333 HGCMFunctionParameter f32Format;
334 } Msg;
335
336 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
337 Msg.id64Context.SetUInt64(VBOX_SHCL_HOST_MSG_READ_DATA_CID);
338 Msg.f32Format.SetUInt32(0);
339
340 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
341 if (RT_SUCCESS(rc))
342 {
343 rc = Msg.id64Context.GetUInt64(&pCtx->idContext);
344 AssertRC(rc);
345 int rc2 = Msg.f32Format.GetUInt32(pfFormat);
346 AssertRCStmt(rc2, rc = rc2);
347 }
348
349 LogFlowFuncLeaveRC(rc);
350 return rc;
351}
352
353
354/**
355 * Fetches a VBOX_SHCL_HOST_MSG_READ_DATA message.
356 *
357 * @returns VBox status code.
358 * @param pCtx Shared Clipboard command context to use for the connection.
359 * @param pfFormat Where to return the requested format.
360 */
361static int vbglR3ClipboardFetchReadData(PVBGLR3SHCLCMDCTX pCtx, PSHCLFORMAT pfFormat)
362{
363 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
364 AssertPtrReturn(pfFormat, VERR_INVALID_POINTER);
365
366 struct
367 {
368 VBGLIOCHGCMCALL Hdr;
369 HGCMFunctionParameter id32Msg;
370 HGCMFunctionParameter f32Format;
371 } Msg;
372
373 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_GET, 2);
374 Msg.id32Msg.SetUInt32(VBOX_SHCL_HOST_MSG_READ_DATA);
375 Msg.f32Format.SetUInt32(0);
376
377 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
378 if (RT_SUCCESS(rc))
379 {
380 rc = Msg.f32Format.GetUInt32(pfFormat);
381 AssertRC(rc);
382 }
383
384 LogFlowFuncLeaveRC(rc);
385 return rc;
386}
387
388
389/**
390 * Get a host message, legacy version (which does not have VBOX_SHCL_GUEST_FN_MSG_GET). Do not use anymore.
391 *
392 * Note: This is the old message which still is being used for the non-URI Shared Clipboard transfers,
393 * to not break compatibility with older additions / VBox versions.
394 *
395 * This will block until a message becomes available.
396 *
397 * @returns VBox status code.
398 * @param idClient The client id returned by VbglR3ClipboardConnect().
399 * @param pidMsg Where to store the message id.
400 * @param pfFormats Where to store the format(s) the message applies to.
401 */
402VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pidMsg, uint32_t *pfFormats)
403{
404 VBoxShClGetHostMsgOld Msg;
405
406 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT, VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD);
407 VbglHGCMParmUInt32Set(&Msg.msg, 0);
408 VbglHGCMParmUInt32Set(&Msg.formats, 0);
409
410 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
411 if (RT_SUCCESS(rc))
412 {
413 int rc2 = VbglHGCMParmUInt32Get(&Msg.msg, pidMsg);
414 if (RT_SUCCESS(rc))
415 {
416 rc2 = VbglHGCMParmUInt32Get(&Msg.formats, pfFormats);
417 if (RT_SUCCESS(rc2))
418 return rc;
419 }
420 rc = rc2;
421 }
422 *pidMsg = UINT32_MAX - 1;
423 *pfFormats = UINT32_MAX;
424 return rc;
425}
426
427
428/**
429 * Reads data from the host clipboard.
430 *
431 * @returns VBox status code.
432 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
433 *
434 * @param idClient The client id returned by VbglR3ClipboardConnect().
435 * @param fFormat The format we're requesting the data in.
436 * @param pvData Where to store the data.
437 * @param cbData The size of the buffer pointed to by \a pvData.
438 * This also indicates the maximum size to read.
439 * @param pcbRead The actual size of the host clipboard data. May be larger than \a cbData.
440 */
441VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pvData, uint32_t cbData,
442 uint32_t *pcbRead)
443{
444 LogFlowFunc(("fFormat=%#x, pvData=%p, cbData=%RU32\n", fFormat, pvData, cbData));
445
446 struct
447 {
448 VBGLIOCHGCMCALL Hdr;
449 VBoxShClParmDataRead Parms;
450 } Msg;
451
452 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_READ, VBOX_SHCL_CPARMS_DATA_READ);
453 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
454 VbglHGCMParmPtrSet( &Msg.Parms.pData, pvData, cbData);
455 VbglHGCMParmUInt32Set(&Msg.Parms.cb32Needed, 0);
456
457 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
458 if (RT_SUCCESS(rc))
459 {
460 uint32_t cbRead;
461 rc = VbglHGCMParmUInt32Get(&Msg.Parms.cb32Needed, &cbRead);
462 if (RT_SUCCESS(rc))
463 {
464 LogFlowFunc(("cbRead=%RU32\n", cbRead));
465
466 if (cbRead > cbData)
467 rc = VINF_BUFFER_OVERFLOW;
468
469 *pcbRead = cbRead;
470 }
471 }
472
473 LogFlowFuncLeaveRC(rc);
474 return rc;
475}
476
477
478/**
479 * Reads clipboard data from the host clipboard.
480 *
481 * @returns VBox status code.
482 * @retval VINF_BUFFER_OVERFLOW If there is more data available than the caller provided buffer space for.
483 *
484 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
485 * @param uFormat Clipboard format of clipboard data to be read.
486 * @param pvData Buffer where to store the read data.
487 * @param cbData Size (in bytes) of data buffer where to store the read data.
488 * @param pcbRead The actual size of the host clipboard data.
489 */
490VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx,
491 SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead)
492{
493 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
494 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
495 return VbglR3ClipboardReadData(pCtx->idClient, uFormat, pvData, cbData, pcbRead);
496}
497
498
499/**
500 * Query the host features.
501 *
502 * @returns VBox status code.
503 * @param idClient The client ID returned by VbglR3ClipboardConnect().
504 * @param pfHostFeatures Where to store the host feature, VBOX_SHCL_HF_XXX.
505 */
506VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures)
507{
508 int rc;
509 do
510 {
511 struct
512 {
513 VBGLIOCHGCMCALL Hdr;
514 HGCMFunctionParameter f64Features0;
515 HGCMFunctionParameter f64Features1;
516 } Msg;
517 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_QUERY_FEATURES, 2);
518 VbglHGCMParmUInt64Set(&Msg.f64Features0, 0);
519 VbglHGCMParmUInt64Set(&Msg.f64Features1, RT_BIT_64(63));
520
521 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
522 if (RT_SUCCESS(rc))
523 {
524 Assert(Msg.f64Features0.type == VMMDevHGCMParmType_64bit);
525 Assert(Msg.f64Features1.type == VMMDevHGCMParmType_64bit);
526 if (Msg.f64Features1.u.value64 & RT_BIT_64(63))
527 rc = VERR_NOT_SUPPORTED;
528 else if (pfHostFeatures)
529 *pfHostFeatures = Msg.f64Features0.u.value64;
530 break;
531 }
532 } while (rc == VERR_INTERRUPTED);
533 return rc;
534
535}
536
537/**
538 * Peeks at the next host message, extended version.
539 *
540 * This glosses over the difference between new (6.1) and old (1.3.2) host
541 * service versions, however it does so by abusing @a pcParameters, so don't use
542 * it directly when in legacy mode, always pass it on to
543 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
544 *
545 * @returns VBox status code.
546 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
547 * caller just have to repeat this call.
548 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
549 * @retval VERR_TRY_AGAIN if no new message is available.
550 *
551 * @param pCtx Shared Clipboard command context to use for the connection.
552 * @param fWait Wait for new messages to arrive if \c true, return immediately if \c false.
553 * @param pidMsg Where to store the message id.
554 * @param pcParameters Where to store the number of parameters which will
555 * be received in a second call to the host.
556 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
557 * for the VM restore check. Optional.
558 *
559 * @note Restore check is only performed optimally with a 6.0 host.
560 */
561static int vbglR3ClipboardMsgPeekEx(PVBGLR3SHCLCMDCTX pCtx, bool fWait, uint32_t *pidMsg,
562 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
563{
564 AssertPtrReturn(pidMsg, VERR_INVALID_POINTER);
565 AssertPtrReturn(pcParameters, VERR_INVALID_POINTER);
566
567 struct
568 {
569 VBGLIOCHGCMCALL Hdr;
570 HGCMFunctionParameter idMsg; /* Doubles as restore check on input. */
571 HGCMFunctionParameter cParameters;
572 } Msg;
573 int rc;
574 if (!pCtx->fUseLegacyProtocol)
575 {
576 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient,
577 fWait ? VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT
578 : VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT, 2);
579 VbglHGCMParmUInt64Set(&Msg.idMsg, pidRestoreCheck ? *pidRestoreCheck : 0);
580 VbglHGCMParmUInt32Set(&Msg.cParameters, 0);
581 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
582 Log4Func(("VbglR3HGCMCall -> %Rrc\n", rc));
583 if (RT_SUCCESS(rc))
584 {
585 AssertMsgReturn( Msg.idMsg.type == VMMDevHGCMParmType_64bit
586 && Msg.cParameters.type == VMMDevHGCMParmType_32bit,
587 ("msg.type=%d num_parms.type=%d\n", Msg.idMsg.type, Msg.cParameters.type),
588 VERR_INTERNAL_ERROR_3);
589
590 *pidMsg = (uint32_t)Msg.idMsg.u.value64;
591 *pcParameters = Msg.cParameters.u.value32;
592 return rc;
593 }
594
595 /*
596 * If restored, update pidRestoreCheck.
597 */
598 if (rc == VERR_VM_RESTORED && pidRestoreCheck)
599 *pidRestoreCheck = Msg.idMsg.u.value64;
600 }
601 else
602 {
603 /*
604 * We do some crude stuff here by putting the 2nd parameter (foramts) in the parameter count,
605 * however it's supposed to be passed directly to VbglR3ClipboardEventGetNext or
606 * VbglR3ClipboardEventGetNextEx, so that's fine...
607 */
608 rc = VbglR3ClipboardGetHostMsgOld(pCtx->idClient, pidMsg, pcParameters);
609 if (RT_SUCCESS(rc))
610 return rc;
611 }
612
613 /*
614 * If interrupted we must cancel the call so it doesn't prevent us from making another one.
615 */
616 if (rc == VERR_INTERRUPTED)
617 {
618 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_MSG_CANCEL, 0);
619 int rc2 = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg.Hdr));
620 AssertRC(rc2);
621 }
622
623 *pidMsg = UINT32_MAX - 1;
624 *pcParameters = UINT32_MAX - 2;
625 return rc;
626}
627
628/**
629 * Peeks at the next host message, waiting for one to turn up.
630 *
631 * This glosses over the difference between new (6.1) and old (1.3.2) host
632 * service versions, however it does so by abusing @a pcParameters, so don't use
633 * it directly when in legacy mode, always pass it on to
634 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
635 *
636 * @returns VBox status code.
637 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
638 * caller just have to repeat this call.
639 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
640 *
641 * @param pCtx Shared Clipboard command context to use for the connection.
642 * @param pidMsg Where to store the message id.
643 * @param pcParameters Where to store the number of parameters which will
644 * be received in a second call to the host.
645 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
646 * for the VM restore check. Optional.
647 *
648 * @note Restore check is only performed optimally with a 6.0 host.
649 */
650VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
651 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
652{
653 return vbglR3ClipboardMsgPeekEx(pCtx, true /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
654}
655
656/**
657 * Peeks at the next host message, returning immediately.
658 *
659 * This glosses over the difference between new (6.1) and old (1.3.2) host
660 * service versions, however it does so by abusing @a pcParameters, so don't use
661 * it directly when in legacy mode, always pass it on to
662 * VbglR3ClipboardEventGetNext() or VbglR3ClipboardEventGetNextEx().
663 *
664 * @returns VBox status code.
665 * @retval VERR_INTERRUPTED if interrupted. Does the necessary cleanup, so
666 * caller just have to repeat this call.
667 * @retval VERR_VM_RESTORED if the VM has been restored (idRestoreCheck).
668 * @retval VERR_TRY_AGAIN if no new message is available.
669 *
670 * @param pCtx Shared Clipboard command context to use for the connection.
671 * @param pidMsg Where to store the message id.
672 * @param pcParameters Where to store the number of parameters which will
673 * be received in a second call to the host.
674 * @param pidRestoreCheck Pointer to the VbglR3GetSessionId() variable to use
675 * for the VM restore check. Optional.
676 *
677 * @note Restore check is only performed optimally with a 6.0 host.
678 */
679VBGLR3DECL(int) VbglR3ClipboardMsgPeek(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg,
680 uint32_t *pcParameters, uint64_t *pidRestoreCheck)
681{
682 return vbglR3ClipboardMsgPeekEx(pCtx, false /* fWait */, pidMsg, pcParameters, pidRestoreCheck);
683}
684
685#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
686
687/**
688 * Reads a transfer root list header from the host.
689 *
690 * @returns VBox status code.
691 * @param pCtx Shared Clipboard command context to use for the connection.
692 * @param pRootListHdr Where to store the received root list header.
693 */
694static int vbglR3ClipboardTransferRootListHdrRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
695{
696 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
697 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
698
699 VBoxShClRootListHdrMsg Msg;
700
701 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
702 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ);
703
704 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
705 Msg.ReqParms.fRoots.SetUInt32(0);
706
707 Msg.cRoots.SetUInt64(0);
708
709 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
710 if (RT_SUCCESS(rc))
711 {
712 rc = Msg.ReqParms.fRoots.GetUInt32(&pRootListHdr->fFeatures); AssertRC(rc);
713 if (RT_SUCCESS(rc))
714 {
715 rc = Msg.cRoots.GetUInt64(&pRootListHdr->cEntries);
716 AssertRC(rc);
717
718 pRootListHdr->cbTotalSize = 0; /* Unused for the root list header. */
719 }
720 }
721 else
722 LogRel(("Shared Clipboard: Reading root list header failed: %Rrc\n", rc));
723
724 LogFlowFuncLeaveRC(rc);
725 return rc;
726}
727
728/**
729 * Reads a transfer root list entry from the host.
730 *
731 * @returns VBox status code.
732 * @param pCtx Shared Clipboard command context to use for the connection.
733 * @param uIndex Index of root list entry to read.
734 * @param pRootListEntry Where to store the root list entry read from the host.
735 */
736static int vbglR3ClipboardTransferRootListEntryRead(PVBGLR3SHCLCMDCTX pCtx, uint64_t uIndex, PSHCLLISTENTRY pRootListEntry)
737{
738 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
739 AssertPtrReturn(pRootListEntry, VERR_INVALID_POINTER);
740
741 VBoxShClRootListEntryMsg Msg;
742
743 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
744 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ);
745
746 uint32_t const fInfo = VBOX_SHCL_INFO_F_FSOBJINFO; /* For now the only info we have. */
747
748 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
749 Msg.Parms.fInfo.SetUInt32(fInfo);
750 Msg.Parms.uIndex.SetUInt64(uIndex);
751
752 char szName[SHCLLISTENTRY_MAX_NAME];
753 Msg.szName.SetPtr(szName, sizeof(szName));
754
755 void *pvInfo = NULL;
756 uint32_t cbInfo = 0;
757
758 int rc = VINF_SUCCESS;
759
760 if ((fInfo & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO)
761 {
762 cbInfo = sizeof(SHCLFSOBJINFO);
763 pvInfo = RTMemAlloc(cbInfo);
764 if (!pvInfo)
765 rc = VERR_NO_MEMORY;
766 }
767
768 if (RT_SUCCESS(rc))
769 {
770 Msg.cbInfo.SetUInt32(cbInfo);
771 Msg.pvInfo.SetPtr(pvInfo, cbInfo);
772
773 rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
774 if (RT_SUCCESS(rc))
775 {
776 uint32_t fInfoRet;
777 rc = Msg.Parms.fInfo.GetUInt32(&fInfoRet);
778 AssertRCReturn(rc, rc);
779 AssertMsgStmt((fInfoRet & VBOX_SHCL_INFO_F_FSOBJINFO) == VBOX_SHCL_INFO_F_FSOBJINFO,
780 ("Host returned unknown entry info flags (%#x)\n", fInfoRet), rc = VERR_INVALID_PARAMETER);
781 if (RT_SUCCESS(rc))
782 {
783 uint32_t cbInfoRet = 0;
784 Msg.cbInfo.GetUInt32(&cbInfoRet);
785
786 AssertMsgStmt(cbInfo == cbInfoRet,
787 ("Host reported cbInfo %RU32, expected %RU32\n", cbInfoRet, cbInfo), rc = VERR_INVALID_PARAMETER);
788
789 rc = ShClTransferListEntryInitEx(pRootListEntry, fInfo, szName, pvInfo, cbInfo);
790 if (RT_SUCCESS(rc))
791 {
792 pvInfo = NULL; /* Entry took ownership of pvInfo now. */
793 cbInfo = 0;
794 }
795 }
796 }
797 else
798 LogRel(("Shared Clipboard: Reading root list entry failed: %Rrc\n", rc));
799 }
800
801 RTMemFree(pvInfo);
802
803 LogFlowFuncLeaveRC(rc);
804 return rc;
805}
806
807/**
808 * Reads the transfer root list from the host.
809 *
810 * @returns VBox status code.
811 * @param pCtx Shared Clipboard command context to use for the connection.
812 * @param pTransfer Transfer to read root list for.
813 * Must be in INITIALIZED state.
814 */
815VBGLR3DECL(int) VbglR3ClipboardTransferRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer)
816{
817 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
818 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
819
820 AssertMsgReturn(ShClTransferGetStatus(pTransfer) == SHCLTRANSFERSTATUS_INITIALIZED,
821 ("Can't read root list -- wrong transfer status\n"), VERR_WRONG_ORDER);
822
823 SHCLLISTHDR Hdr;
824 int rc = vbglR3ClipboardTransferRootListHdrRead(pCtx, &Hdr);
825 if (RT_SUCCESS(rc))
826 {
827 LogFlowFunc(("cEntries=%RU64, cTotalSize=%RU64\n", Hdr.cEntries, Hdr.cbTotalSize));
828
829 if (!Hdr.cEntries) /* Should never happen (tm). */
830 {
831#ifdef DEBUG_andy
832 AssertFailed();
833#endif
834 LogRel(("Shared Clipboard: Warning: Transfer %RU32 has no entries\n", ShClTransferGetID(pTransfer)));
835 }
836
837 for (uint64_t i = 0; i < Hdr.cEntries; i++)
838 {
839 PSHCLLISTENTRY pEntry = NULL;
840 rc = ShClTransferListEntryAlloc(&pEntry);
841 if (RT_SUCCESS(rc))
842 {
843 rc = vbglR3ClipboardTransferRootListEntryRead(pCtx, i, pEntry);
844 if (RT_SUCCESS(rc))
845 rc = ShClTransferListAddEntry(&pTransfer->lstRoots, pEntry, true /* fAppend */);
846 }
847
848 if (RT_FAILURE(rc))
849 {
850 ShClTransferListEntryFree(pEntry);
851 break;
852 }
853 }
854 }
855 else
856 LogRel(("Shared Clipboard: Reading root list for transfer %RU32 failed: %Rrc\n", ShClTransferGetID(pTransfer), rc));
857
858 LogFlowFuncLeaveRC(rc);
859 return rc;
860}
861
862/**
863 * Receives a transfer status from the host.
864 *
865 * @returns VBox status code.
866 * @param pCtx Shared Clipboard command context to use for the connection.
867 * @param pEnmDir Where to store the transfer direction for the reported transfer.
868 * @param pReport Where to store the transfer (status) report.
869 */
870VBGLR3DECL(int) VbglR3ClipboarTransferStatusRecv(PVBGLR3SHCLCMDCTX pCtx,
871 PSHCLTRANSFERDIR pEnmDir, PSHCLTRANSFERREPORT pReport)
872{
873 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
874 AssertPtrReturn(pReport, VERR_INVALID_POINTER);
875 AssertPtrReturn(pEnmDir, VERR_INVALID_POINTER);
876
877 VBoxShClTransferStatusMsg Msg;
878 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
879 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_TRANSFER_STATUS);
880
881 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_STATUS);
882 Msg.enmDir.SetUInt32(0);
883 Msg.enmStatus.SetUInt32(0);
884 Msg.rc.SetUInt32(0);
885 Msg.fFlags.SetUInt32(0);
886
887 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
888 if (RT_SUCCESS(rc))
889 {
890 rc = Msg.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
891 if (RT_SUCCESS(rc))
892 {
893 rc = Msg.enmDir.GetUInt32((uint32_t *)pEnmDir);
894 AssertRC(rc);
895 }
896 if (RT_SUCCESS(rc))
897 {
898 rc = Msg.enmStatus.GetUInt32(&pReport->uStatus);
899 AssertRC(rc);
900 }
901 if (RT_SUCCESS(rc))
902 {
903 rc = Msg.rc.GetUInt32((uint32_t *)&pReport->rc);
904 AssertRC(rc);
905 }
906 if (RT_SUCCESS(rc))
907 {
908 rc = Msg.fFlags.GetUInt32(&pReport->fFlags);
909 AssertRC(rc);
910 }
911 }
912
913 LogFlowFuncLeaveRC(rc);
914 return rc;
915}
916
917/**
918 * Replies to a transfer report from the host, extended version.
919 *
920 * @returns VBox status code.
921 * @param pCtx Shared Clipboard command context to use for the connection.
922 * @param uCID Context ID to use.
923 * The transfer ID is part of this.
924 * @param uStatus Tranfer status to reply.
925 * @param rcTransfer Result code (rc) to reply.
926 */
927static int vbglR3ClipboardTransferStatusReplyEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t uCID,
928 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
929{
930 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
931
932 VBoxShClReplyMsg Msg;
933 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
934 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
935
936 Msg.uContext.SetUInt64(uCID);
937 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_TRANSFER_STATUS);
938 Msg.rc.SetUInt32((uint32_t )rcTransfer); /* int vs. uint32_t */
939 Msg.pvPayload.SetPtr(NULL, 0);
940
941 Msg.u.TransferStatus.enmStatus.SetUInt32((uint32_t)uStatus);
942
943 LogFlowFunc(("%s\n", ShClTransferStatusToStr(uStatus)));
944
945 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
946
947 LogFlowFuncLeaveRC(rc);
948 return rc;
949}
950
951/**
952 * Replies to a transfer report from the host.
953 *
954 * @returns VBox status code.
955 * @param pCtx Shared Clipboard command context to use for the connection.
956 * @param pTransfer Transfer of report to reply to.
957 * @param uStatus Tranfer status to reply.
958 * @param rcTransfer Result code (rc) to reply.
959 */
960VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer,
961 SHCLTRANSFERSTATUS uStatus, int rcTransfer)
962{
963 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
964 AssertPtrReturn(pTransfer, VERR_INVALID_POINTER);
965
966 int rc = vbglR3ClipboardTransferStatusReplyEx(pCtx, pCtx->idContext, uStatus, rcTransfer);
967
968 LogFlowFuncLeaveRC(rc);
969 return rc;
970}
971
972/**
973 * Receives a host request to read a transfer root list header from the guest.
974 *
975 * @returns VBox status code.
976 * @param pCtx Shared Clipboard command context to use for the connection.
977 * @param pfRoots Where to store the root list header flags to use, requested by the host.
978 */
979VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots)
980{
981 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
982 AssertPtrReturn(pfRoots, VERR_INVALID_POINTER);
983
984 VBoxShClRootListReadReqMsg Msg;
985 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
986 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ);
987
988 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ);
989 Msg.ReqParms.fRoots.SetUInt32(0);
990
991 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
992 if (RT_SUCCESS(rc))
993 {
994 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
995 if (RT_SUCCESS(rc))
996 {
997 rc = Msg.ReqParms.fRoots.GetUInt32(pfRoots);
998 AssertRC(rc);
999 }
1000 }
1001
1002 LogFlowFuncLeaveRC(rc);
1003 return rc;
1004}
1005
1006/**
1007 * Replies to a transfer root list header request.
1008 *
1009 * @returns VBox status code.
1010 * @param pCtx Shared Clipboard command context to use for the connection.
1011 * @param pRootListHdr Root lsit header to reply to the host.
1012 */
1013VBGLR3DECL(int) VbglR3ClipboardTransferRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHDR pRootListHdr)
1014{
1015 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1016 AssertPtrReturn(pRootListHdr, VERR_INVALID_POINTER);
1017
1018 VBoxShClRootListHdrMsg Msg;
1019 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1020 VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE);
1021
1022 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1023 Msg.ReqParms.fRoots.SetUInt32(pRootListHdr->fFeatures);
1024
1025 Msg.cRoots.SetUInt64(pRootListHdr->cEntries);
1026
1027 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1028
1029 LogFlowFuncLeaveRC(rc);
1030 return rc;
1031}
1032
1033/**
1034 * Receives a host request to read a transfer root list entry from the guest.
1035 *
1036 * @returns VBox status code.
1037 * @param pCtx Shared Clipboard command context to use for the connection.
1038 * @param puIndex Where to return the index of the root list entry the host wants to read.
1039 * @param pfInfo Where to return the read flags the host wants to use.
1040 */
1041VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReq(PVBGLR3SHCLCMDCTX pCtx, uint64_t *puIndex, uint32_t *pfInfo)
1042{
1043 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1044 AssertPtrReturn(puIndex, VERR_INVALID_POINTER);
1045 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1046
1047 VBoxShClRootListEntryReadReqMsg Msg;
1048 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1049 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ);
1050
1051 Msg.Parms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ);
1052 Msg.Parms.fInfo.SetUInt32(0);
1053 Msg.Parms.uIndex.SetUInt64(0);
1054
1055 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1056 if (RT_SUCCESS(rc))
1057 {
1058 rc = Msg.Parms.uContext.GetUInt64(&pCtx->idContext); AssertRC(rc);
1059 if (RT_SUCCESS(rc))
1060 {
1061 rc = Msg.Parms.fInfo.GetUInt32(pfInfo);
1062 AssertRC(rc);
1063 }
1064 if (RT_SUCCESS(rc))
1065 {
1066 rc = Msg.Parms.uIndex.GetUInt64(puIndex);
1067 AssertRC(rc);
1068 }
1069 }
1070
1071 LogFlowFuncLeaveRC(rc);
1072 return rc;
1073}
1074
1075/**
1076 * Replies to a transfer root list entry read request from the host.
1077 *
1078 * @returns VBox status code.
1079 * @param pCtx Shared Clipboard command context to use for the connection.
1080 * @param uIndex Index of root list entry to reply.
1081 * @param pEntry Actual root list entry to reply.
1082 */
1083VBGLR3DECL(int) VbglR3ClipboardTransferRootListEntryReadReply(PVBGLR3SHCLCMDCTX pCtx, uint32_t uIndex, PSHCLLISTENTRY pEntry)
1084{
1085 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1086 AssertPtrReturn(pEntry, VERR_INVALID_POINTER);
1087
1088 VBoxShClRootListEntryMsg Msg;
1089 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1090 VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE);
1091
1092 Msg.Parms.uContext.SetUInt64(pCtx->idContext);
1093 Msg.Parms.fInfo.SetUInt32(pEntry->fInfo);
1094 Msg.Parms.uIndex.SetUInt64(uIndex);
1095
1096 Msg.szName.SetPtr(pEntry->pszName, pEntry->cbName);
1097 Msg.cbInfo.SetUInt32(pEntry->cbInfo);
1098 Msg.pvInfo.SetPtr(pEntry->pvInfo, pEntry->cbInfo);
1099
1100 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1101
1102 LogFlowFuncLeaveRC(rc);
1103 return rc;
1104}
1105
1106/**
1107 * Sends a request to open a transfer list handle to the host.
1108 *
1109 * @returns VBox status code.
1110 * @param pCtx Shared Clipboard command context to use for the connection.
1111 * @param pOpenParms List open parameters to use for the open request.
1112 * @param phList Where to return the list handle received from the host.
1113 */
1114VBGLR3DECL(int) VbglR3ClipboardTransferListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1115 PSHCLLISTHANDLE phList)
1116{
1117 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1118 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1119 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1120
1121 VBoxShClListOpenMsg Msg;
1122 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1123 VBOX_SHCL_GUEST_FN_LIST_OPEN, VBOX_SHCL_CPARMS_LIST_OPEN);
1124
1125 Msg.uContext.SetUInt64(pCtx->idContext);
1126 Msg.fList.SetUInt32(0);
1127 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1128 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1129 Msg.uHandle.SetUInt64(0);
1130
1131 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1132 if (RT_SUCCESS(rc))
1133 {
1134 rc = Msg.uHandle.GetUInt64(phList); AssertRC(rc);
1135 }
1136
1137 LogFlowFuncLeaveRC(rc);
1138 return rc;
1139}
1140
1141/**
1142 * Receives a host request to open a transfer list handle on the guest.
1143 *
1144 * @returns VBox status code.
1145 * @param pCtx Shared Clipboard command context to use for the connection.
1146 * @param pOpenParms Where to store the open parameters the host wants to use for opening the list handle.
1147 */
1148VBGLR3DECL(int) VbglR3ClipboardTransferListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms)
1149{
1150 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1151 AssertPtrReturn(pOpenParms, VERR_INVALID_POINTER);
1152
1153 VBoxShClListOpenMsg Msg;
1154 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1155 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_OPEN);
1156
1157 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN);
1158 Msg.fList.SetUInt32(0);
1159 Msg.pvPath.SetPtr(pOpenParms->pszPath, pOpenParms->cbPath);
1160 Msg.pvFilter.SetPtr(pOpenParms->pszFilter, pOpenParms->cbFilter);
1161 Msg.uHandle.SetUInt64(0);
1162
1163 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1164 if (RT_SUCCESS(rc))
1165 {
1166 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1167 if (RT_SUCCESS(rc))
1168 rc = Msg.fList.GetUInt32(&pOpenParms->fList);
1169 }
1170
1171 LogFlowFuncLeaveRC(rc);
1172 return rc;
1173}
1174
1175/**
1176 * Replies to a transfer list open request from the host.
1177 *
1178 * @returns VBox status code.
1179 * @param pCtx Shared Clipboard command context to use for the connection.
1180 * @param rcReply Return code to reply to the host.
1181 * @param hList List handle of (guest) list to reply to the host.
1182 */
1183VBGLR3DECL(int) VbglR3ClipboardTransferListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1184{
1185 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1186
1187 VBoxShClReplyMsg Msg;
1188 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1189 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1190
1191 Msg.uContext.SetUInt64(pCtx->idContext);
1192 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_OPEN);
1193 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1194 Msg.pvPayload.SetPtr(NULL, 0);
1195
1196 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1197
1198 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1199
1200 LogFlowFuncLeaveRC(rc);
1201 return rc;
1202}
1203
1204/**
1205 * Receives a host request to close a list handle on the guest.
1206 *
1207 * @returns VBox status code.
1208 * @param pCtx Shared Clipboard command context to use for the connection.
1209 * @param phList Where to store the list handle to close, received from the host.
1210 */
1211VBGLR3DECL(int) VbglR3ClipboardTransferListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList)
1212{
1213 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1214 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1215
1216 VBoxShClListCloseMsg Msg;
1217 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1218 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_CLOSE);
1219
1220 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE);
1221 Msg.uHandle.SetUInt64(0);
1222
1223 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1224 if (RT_SUCCESS(rc))
1225 {
1226 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1227 if (RT_SUCCESS(rc))
1228 {
1229 rc = Msg.uHandle.GetUInt64(phList);
1230 AssertRC(rc);
1231 }
1232 }
1233
1234 LogFlowFuncLeaveRC(rc);
1235 return rc;
1236}
1237
1238/**
1239 * Replies to a transfer list handle close request from the host.
1240 *
1241 * @returns VBox status code.
1242 * @param pCtx Shared Clipboard command context to use for the connection.
1243 * @param rcReply Return code to reply to the host.
1244 * @param hList List handle the send the close reply for.
1245 */
1246VBGLR3DECL(int) VbglR3ClipboardTransferListCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList)
1247{
1248 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1249
1250 VBoxShClReplyMsg Msg;
1251 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1252 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1253
1254 Msg.uContext.SetUInt64(pCtx->idContext);
1255 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_LIST_CLOSE);
1256 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1257 Msg.pvPayload.SetPtr(NULL, 0);
1258
1259 Msg.u.ListOpen.uHandle.SetUInt64(hList);
1260
1261 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1262
1263 LogFlowFuncLeaveRC(rc);
1264 return rc;
1265}
1266
1267/**
1268 * Sends a request to close a transfer list handle to the host.
1269 *
1270 * @returns VBox status code.
1271 * @param pCtx Shared Clipboard command context to use for the connection.
1272 * @param hList List handle to request for closing on the host.
1273 */
1274VBGLR3DECL(int) VbglR3ClipboardTransferListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList)
1275{
1276 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1277
1278 VBoxShClListCloseMsg Msg;
1279 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1280 VBOX_SHCL_GUEST_FN_LIST_CLOSE, VBOX_SHCL_CPARMS_LIST_CLOSE);
1281
1282 Msg.uContext.SetUInt64(pCtx->idContext);
1283 Msg.uHandle.SetUInt64(hList);
1284
1285 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1286
1287 LogFlowFuncLeaveRC(rc);
1288 return rc;
1289}
1290
1291/**
1292 * Sends a request to read a transfer list header to the host.
1293 *
1294 * @returns VBox status code.
1295 * @param pCtx Shared Clipboard command context to use for the connection.
1296 * @param hList List handle to read list header for.
1297 * @param fFlags List header read flags to use.
1298 * @param pListHdr Where to return the list header received from the host.
1299 */
1300VBGLR3DECL(int) VbglR3ClipboardTransferListHdrRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, uint32_t fFlags,
1301 PSHCLLISTHDR pListHdr)
1302{
1303 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1304 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1305
1306 VBoxShClListHdrMsg Msg;
1307 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1308 VBOX_SHCL_GUEST_FN_LIST_HDR_READ, VBOX_SHCL_CPARMS_LIST_HDR);
1309
1310 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1311 Msg.ReqParms.uHandle.SetUInt64(hList);
1312 Msg.ReqParms.fFlags.SetUInt32(fFlags);
1313
1314 Msg.fFeatures.SetUInt32(0);
1315 Msg.cbTotalSize.SetUInt32(0);
1316 Msg.cTotalObjects.SetUInt64(0);
1317 Msg.cbTotalSize.SetUInt64(0);
1318
1319 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1320 if (RT_SUCCESS(rc))
1321 {
1322 rc = Msg.fFeatures.GetUInt32(&pListHdr->fFeatures);
1323 if (RT_SUCCESS(rc))
1324 rc = Msg.cTotalObjects.GetUInt64(&pListHdr->cEntries);
1325 if (RT_SUCCESS(rc))
1326 rc = Msg.cbTotalSize.GetUInt64(&pListHdr->cbTotalSize);
1327 }
1328
1329 LogFlowFuncLeaveRC(rc);
1330 return rc;
1331}
1332
1333/**
1334 * Receives a host request to read a transfer list header on the guest.
1335 *
1336 * @returns VBox status code.
1337 * @param pCtx Shared Clipboard command context to use for the connection.
1338 * @param phList Where to return the list handle to read list header for.
1339 * @param pfFlags Where to return the List header read flags to use.
1340 */
1341VBGLR3DECL(int) VbglR3ClipboardTransferListHdrReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfFlags)
1342{
1343 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1344 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1345 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1346
1347 VBoxShClListHdrReadReqMsg Msg;
1348 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1349 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ);
1350
1351 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ);
1352 Msg.ReqParms.uHandle.SetUInt64(0);
1353 Msg.ReqParms.fFlags.SetUInt32(0);
1354
1355 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1356 if (RT_SUCCESS(rc))
1357 {
1358 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1359 if (RT_SUCCESS(rc))
1360 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1361 if (RT_SUCCESS(rc))
1362 rc = Msg.ReqParms.fFlags.GetUInt32(pfFlags);
1363 }
1364
1365 LogFlowFuncLeaveRC(rc);
1366 return rc;
1367}
1368
1369/**
1370 * Sends (writes) a transfer list header to the host.
1371 *
1372 * @returns VBox status code.
1373 * @param pCtx Shared Clipboard command context to use for the connection.
1374 * @param hList List handle to write list header for.
1375 * @param pListHdr List header to write.
1376 */
1377VBGLR3DECL(int) VbglR3ClipboardTransferListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1378 PSHCLLISTHDR pListHdr)
1379{
1380 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1381 AssertPtrReturn(pListHdr, VERR_INVALID_POINTER);
1382
1383 VBoxShClListHdrMsg Msg;
1384 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1385 VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE, VBOX_SHCL_CPARMS_LIST_HDR);
1386
1387 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1388 Msg.ReqParms.uHandle.SetUInt64(hList);
1389 Msg.ReqParms.fFlags.SetUInt32(0);
1390
1391 Msg.fFeatures.SetUInt32(0);
1392 Msg.cbTotalSize.SetUInt32(pListHdr->fFeatures);
1393 Msg.cTotalObjects.SetUInt64(pListHdr->cEntries);
1394 Msg.cbTotalSize.SetUInt64(pListHdr->cbTotalSize);
1395
1396 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1397
1398 LogFlowFuncLeaveRC(rc);
1399 return rc;
1400}
1401
1402/**
1403 * Sends a request to read a transfer list entry from the host.
1404 *
1405 * @returns VBox status code.
1406 * @param pCtx Shared Clipboard command context to use for the connection.
1407 * @param hList List handle to request to read a list entry for.
1408 * @param pListEntry Where to return the list entry read from the host.
1409 */
1410VBGLR3DECL(int) VbglR3ClipboardTransferListEntryRead(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1411 PSHCLLISTENTRY pListEntry)
1412{
1413 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1414 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1415
1416 VBoxShClListEntryMsg Msg;
1417 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1418 VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ, VBOX_SHCL_CPARMS_LIST_ENTRY);
1419
1420 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1421 Msg.ReqParms.uHandle.SetUInt64(hList);
1422 Msg.ReqParms.fInfo.SetUInt32(0);
1423
1424 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1425 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1426 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1427
1428 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1429 if (RT_SUCCESS(rc))
1430 {
1431 rc = Msg.cbInfo.GetUInt32(&pListEntry->cbInfo); AssertRC(rc);
1432 }
1433
1434 LogFlowFuncLeaveRC(rc);
1435 return rc;
1436}
1437
1438/**
1439 * Receives a host request to read a transfer list entry from the guest.
1440 *
1441 * @returns VBox status code.
1442 * @param pCtx Shared Clipboard command context to use for the connection.
1443 * @param phList Where to return the list handle to read a list entry for.
1444 * @param pfInfo Where to return the list read flags.
1445 */
1446VBGLR3DECL(int) VbglR3ClipboardTransferListEntryReadRecvReq(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList, uint32_t *pfInfo)
1447{
1448 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1449 AssertPtrReturn(phList, VERR_INVALID_POINTER);
1450 AssertPtrReturn(pfInfo, VERR_INVALID_POINTER);
1451
1452 VBoxShClListEntryReadReqMsg Msg;
1453 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1454 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_LIST_ENTRY_READ);
1455
1456 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ);
1457 Msg.ReqParms.uHandle.SetUInt64(0);
1458 Msg.ReqParms.fInfo.SetUInt32(0);
1459
1460 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1461 if (RT_SUCCESS(rc))
1462 {
1463 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1464 if (RT_SUCCESS(rc))
1465 {
1466 rc = Msg.ReqParms.uHandle.GetUInt64(phList);
1467 AssertRC(rc);
1468 }
1469 if (RT_SUCCESS(rc))
1470 {
1471 rc = Msg.ReqParms.fInfo.GetUInt32(pfInfo);
1472 AssertRC(rc);
1473 }
1474 }
1475
1476 LogFlowFuncLeaveRC(rc);
1477 return rc;
1478}
1479
1480/**
1481 * Sends (writes) a transfer list entry to the host.
1482 *
1483 * @returns VBox status code.
1484 * @param pCtx Shared Clipboard command context to use for the connection.
1485 * @param hList List handle to write a list etnry for.
1486 * @param pListEntry List entry to write.
1487 */
1488VBGLR3DECL(int) VbglR3ClipboardTransferListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList,
1489 PSHCLLISTENTRY pListEntry)
1490{
1491 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1492 AssertPtrReturn(pListEntry, VERR_INVALID_POINTER);
1493
1494 VBoxShClListEntryMsg Msg;
1495 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1496 VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE, VBOX_SHCL_CPARMS_LIST_ENTRY);
1497
1498 Msg.ReqParms.uContext.SetUInt64(pCtx->idContext);
1499 Msg.ReqParms.uHandle.SetUInt64(hList);
1500 Msg.ReqParms.fInfo.SetUInt32(pListEntry->fInfo);
1501
1502 Msg.szName.SetPtr(pListEntry->pszName, pListEntry->cbName);
1503 Msg.cbInfo.SetUInt32(pListEntry->cbInfo);
1504 Msg.pvInfo.SetPtr(pListEntry->pvInfo, pListEntry->cbInfo);
1505
1506 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1507
1508 LogFlowFuncLeaveRC(rc);
1509 return rc;
1510}
1511
1512/**
1513 * Receives a host request to open a transfer object on the guest.
1514 *
1515 * @returns VBox status code.
1516 * @param pCtx Shared Clipboard command context to use for the connection.
1517 * @param pCreateParms Where to store the object open/create parameters received from the host.
1518 */
1519VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms)
1520{
1521 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1522 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1523
1524 VBoxShClObjOpenMsg Msg;
1525 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1526 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_OPEN);
1527
1528 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN);
1529 Msg.uHandle.SetUInt64(0);
1530 Msg.szPath.SetPtr(pCreateParms->pszPath, pCreateParms->cbPath);
1531 Msg.fCreate.SetUInt32(0);
1532
1533 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1534 if (RT_SUCCESS(rc))
1535 {
1536 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1537 if (RT_SUCCESS(rc))
1538 rc = Msg.fCreate.GetUInt32(&pCreateParms->fCreate);
1539 }
1540
1541 LogFlowFuncLeaveRC(rc);
1542 return rc;
1543}
1544
1545/**
1546 * Replies a host request to open a transfer object.
1547 *
1548 * @returns VBox status code.
1549 * @param pCtx Shared Clipboard command context to use for the connection.
1550 * @param rcReply Return code to reply to the host.
1551 * @param hObj Object handle of opened object to reply to the host.
1552 */
1553VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1554{
1555 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1556
1557 VBoxShClReplyMsg Msg;
1558 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1559 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1560
1561 Msg.uContext.SetUInt64(pCtx->idContext);
1562 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_OPEN);
1563 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1564 Msg.pvPayload.SetPtr(NULL, 0);
1565
1566 Msg.u.ObjOpen.uHandle.SetUInt64(hObj);
1567
1568 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1569
1570 LogFlowFuncLeaveRC(rc);
1571 return rc;
1572}
1573
1574/**
1575 * Sends a transfer object open request to the host.
1576 *
1577 * @returns VBox status code.
1578 * @param pCtx Shared Clipboard command context to use for the connection.
1579 * @param pCreateParms Object open/create parameters to use for opening the object on the host.
1580 * @param phObj Where to return the object handle from the host.
1581 */
1582VBGLR3DECL(int) VbglR3ClipboardTransferObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms,
1583 PSHCLOBJHANDLE phObj)
1584{
1585 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1586 AssertPtrReturn(pCreateParms, VERR_INVALID_POINTER);
1587 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1588
1589 VBoxShClObjOpenMsg Msg;
1590 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1591 VBOX_SHCL_GUEST_FN_OBJ_OPEN, VBOX_SHCL_CPARMS_OBJ_OPEN);
1592
1593 Msg.uContext.SetUInt64(pCtx->idContext);
1594 Msg.uHandle.SetUInt64(0);
1595 Msg.szPath.SetPtr((void *)pCreateParms->pszPath, pCreateParms->cbPath);
1596 Msg.fCreate.SetUInt32(pCreateParms->fCreate);
1597
1598 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1599 if (RT_SUCCESS(rc))
1600 {
1601 Msg.uHandle.GetUInt64(phObj);
1602 }
1603
1604 LogFlowFuncLeaveRC(rc);
1605 return rc;
1606}
1607
1608/**
1609 * Receives a host request to close a transfer object on the guest.
1610 *
1611 * @returns VBox status code.
1612 * @param pCtx Shared Clipboard command context to use for the connection.
1613 * @param phObj Where to return the object handle to close from the host.
1614 */
1615VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj)
1616{
1617 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1618 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1619
1620 VBoxShClObjCloseMsg Msg;
1621 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1622 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1623
1624 Msg.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE);
1625 Msg.uHandle.SetUInt64(0);
1626
1627 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1628 if (RT_SUCCESS(rc))
1629 {
1630 rc = Msg.uContext.GetUInt64(&pCtx->idContext);
1631 if (RT_SUCCESS(rc))
1632 rc = Msg.uHandle.GetUInt64(phObj);
1633 }
1634
1635 LogFlowFuncLeaveRC(rc);
1636 return rc;
1637}
1638
1639/**
1640 * Replies to a transfer object open request from the host.
1641 *
1642 * @returns VBox status code.
1643 * @param pCtx Shared Clipboard command context to use for the connection.
1644 * @param rcReply Return code to reply to the host.
1645 * @param hObj Object handle to reply to the host.
1646 */
1647VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj)
1648{
1649 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1650
1651 VBoxShClReplyMsg Msg;
1652 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1653 VBOX_SHCL_GUEST_FN_REPLY, VBOX_SHCL_CPARMS_REPLY_MIN + 1);
1654
1655 Msg.uContext.SetUInt64(pCtx->idContext);
1656 Msg.enmType.SetUInt32(VBOX_SHCL_TX_REPLYMSGTYPE_OBJ_CLOSE);
1657 Msg.rc.SetUInt32((uint32_t)rcReply); /** int vs. uint32_t */
1658 Msg.pvPayload.SetPtr(NULL, 0);
1659
1660 Msg.u.ObjClose.uHandle.SetUInt64(hObj);
1661
1662 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1663
1664 LogFlowFuncLeaveRC(rc);
1665 return rc;
1666}
1667
1668/**
1669 * Sends a request to close a transfer object to the host.
1670 *
1671 * @returns VBox status code.
1672 * @param pCtx Shared Clipboard command context to use for the connection.
1673 * @param hObj Object handle to close on the host.
1674 */
1675VBGLR3DECL(int) VbglR3ClipboardTransferObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj)
1676{
1677 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1678
1679 VBoxShClObjCloseMsg Msg;
1680 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1681 VBOX_SHCL_GUEST_FN_OBJ_CLOSE, VBOX_SHCL_CPARMS_OBJ_CLOSE);
1682
1683 Msg.uContext.SetUInt64(pCtx->idContext);
1684 Msg.uHandle.SetUInt64(hObj);
1685
1686 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1687
1688 LogFlowFuncLeaveRC(rc);
1689 return rc;
1690}
1691
1692/**
1693 * Receives a host request to read from a transfer object on the guest.
1694 *
1695 * @returns VBox status code.
1696 * @param pCtx Shared Clipboard command context to use for the connection.
1697 * @param phObj Where to return the object handle to read from.
1698 * @param pcbToRead Where to return the amount (in bytes) to read.
1699 * @param pfFlags Where to return the read flags.
1700 */
1701VBGLR3DECL(int) VbglR3ClipboardTransferObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t *pcbToRead,
1702 uint32_t *pfFlags)
1703{
1704 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1705 AssertPtrReturn(phObj, VERR_INVALID_POINTER);
1706 AssertPtrReturn(pcbToRead, VERR_INVALID_POINTER);
1707 AssertPtrReturn(pfFlags, VERR_INVALID_POINTER);
1708
1709 VBoxShClObjReadReqMsg Msg;
1710 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1711 VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_CPARMS_OBJ_READ_REQ);
1712
1713 Msg.ReqParms.uContext.SetUInt64(VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ);
1714 Msg.ReqParms.uHandle.SetUInt64(0);
1715 Msg.ReqParms.cbToRead.SetUInt32(0);
1716 Msg.ReqParms.fRead.SetUInt32(0);
1717
1718 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1719 if (RT_SUCCESS(rc))
1720 {
1721 rc = Msg.ReqParms.uContext.GetUInt64(&pCtx->idContext);
1722 if (RT_SUCCESS(rc))
1723 rc = Msg.ReqParms.uHandle.GetUInt64(phObj);
1724 if (RT_SUCCESS(rc))
1725 rc = Msg.ReqParms.cbToRead.GetUInt32(pcbToRead);
1726 if (RT_SUCCESS(rc))
1727 rc = Msg.ReqParms.fRead.GetUInt32(pfFlags);
1728 }
1729
1730 LogFlowFuncLeaveRC(rc);
1731 return rc;
1732}
1733
1734/**
1735 * Sends a request to read from a transfer object to the host.
1736 *
1737 * @returns VBox status code.
1738 * @param pCtx Shared Clipboard command context to use for the connection.
1739 * @param hObj Object handle of object to read from.
1740 * @param pvData Buffer where to store the read object data.
1741 * @param cbData Size (in bytes) of buffer.
1742 * @param pcbRead Where to store the amount (in bytes) read from the object.
1743 */
1744VBGLR3DECL(int) VbglR3ClipboardTransferObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1745 void *pvData, uint32_t cbData, uint32_t *pcbRead)
1746{
1747 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1748 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1749 AssertReturn(cbData, VERR_INVALID_PARAMETER);
1750 /* pcbRead is optional. */
1751
1752 VBoxShClObjReadWriteMsg Msg;
1753 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1754 VBOX_SHCL_GUEST_FN_OBJ_READ, VBOX_SHCL_CPARMS_OBJ_READ);
1755
1756 Msg.uContext.SetUInt64(pCtx->idContext);
1757 Msg.uHandle.SetUInt64(hObj);
1758 Msg.cbData.SetUInt32(cbData);
1759 Msg.pvData.SetPtr(pvData, cbData);
1760 Msg.cbChecksum.SetUInt32(0);
1761 Msg.pvChecksum.SetPtr(NULL, 0);
1762
1763 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1764 if (RT_SUCCESS(rc))
1765 {
1766 /** @todo Add checksum support. */
1767
1768 if (pcbRead)
1769 {
1770 rc = Msg.cbData.GetUInt32(pcbRead); AssertRC(rc);
1771 AssertReturn(cbData >= *pcbRead, VERR_TOO_MUCH_DATA);
1772 }
1773 }
1774
1775 LogFlowFuncLeaveRC(rc);
1776 return rc;
1777}
1778
1779/**
1780 * Sends a request to write to a transfer object to the host.
1781 *
1782 * @returns VBox status code.
1783 * @param pCtx Shared Clipboard command context to use for the connection.
1784 * @param hObj Object handle of object to write to.
1785 * @param pvData Buffer of data to write to object.
1786 * @param cbData Size (in bytes) of buffer.
1787 * @param pcbWritten Where to store the amount (in bytes) written to the object.
1788 */
1789VBGLR3DECL(int) VbglR3ClipboardTransferObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj,
1790 void *pvData, uint32_t cbData, uint32_t *pcbWritten)
1791{
1792 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
1793 AssertPtrReturn(pvData, VERR_INVALID_POINTER);
1794 /* cbData can be 0. */
1795 /* pcbWritten is optional. */
1796
1797 VBoxShClObjReadWriteMsg Msg;
1798 VBGL_HGCM_HDR_INIT(&Msg.hdr, pCtx->idClient,
1799 VBOX_SHCL_GUEST_FN_OBJ_WRITE, VBOX_SHCL_CPARMS_OBJ_WRITE);
1800
1801 Msg.uContext.SetUInt64(pCtx->idContext);
1802 Msg.uHandle.SetUInt64(hObj);
1803 Msg.cbData.SetUInt32(cbData);
1804 Msg.pvData.SetPtr(pvData, cbData);
1805 Msg.cbChecksum.SetUInt32(0);
1806 Msg.pvChecksum.SetPtr(NULL, 0);
1807
1808 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
1809 if (RT_SUCCESS(rc))
1810 {
1811 /** @todo Add checksum support. */
1812
1813 if (pcbWritten)
1814 *pcbWritten = cbData; /** @todo For now return all as being written. */
1815 }
1816
1817 LogFlowFuncLeaveRC(rc);
1818 return rc;
1819}
1820
1821
1822/*********************************************************************************************************************************
1823* Transfer interface implementations *
1824*********************************************************************************************************************************/
1825
1826/** @copydoc SHCLTXPROVIDERIFACE::pfnRootListRead */
1827static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceRootListRead(PSHCLTXPROVIDERCTX pCtx)
1828{
1829 LogFlowFuncEnter();
1830
1831 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1832 AssertPtr(pCmdCtx);
1833
1834 int rc = VbglR3ClipboardTransferRootListRead(pCmdCtx, pCtx->pTransfer);
1835
1836 LogFlowFuncLeaveRC(rc);
1837 return rc;
1838}
1839
1840/** @copydoc SHCLTXPROVIDERIFACE::pfnListOpen */
1841static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListOpen(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms,
1842 PSHCLLISTHANDLE phList)
1843{
1844 LogFlowFuncEnter();
1845
1846 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1847 AssertPtr(pCmdCtx);
1848
1849 int rc = VbglR3ClipboardTransferListOpenSend(pCmdCtx, pOpenParms, phList);
1850
1851 LogFlowFuncLeaveRC(rc);
1852 return rc;
1853}
1854
1855/** @copydoc SHCLTXPROVIDERIFACE::pfnListClose */
1856static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListClose(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)
1857{
1858 LogFlowFuncEnter();
1859
1860 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1861 AssertPtr(pCmdCtx);
1862
1863 int rc = VbglR3ClipboardTransferListCloseSend(pCmdCtx, hList);
1864
1865 LogFlowFuncLeaveRC(rc);
1866 return rc;
1867}
1868
1869/** @copydoc SHCLTXPROVIDERIFACE::pfnListHdrRead */
1870static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListHdrRead(PSHCLTXPROVIDERCTX pCtx,
1871 SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)
1872{
1873 LogFlowFuncEnter();
1874
1875 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1876 AssertPtr(pCmdCtx);
1877
1878 int rc = ShClTransferListHdrInit(pListHdr);
1879 if (RT_SUCCESS(rc))
1880 {
1881 if (RT_SUCCESS(rc))
1882 {
1883 rc = VbglR3ClipboardTransferListHdrRead(pCmdCtx, hList, 0 /* fFlags */, pListHdr);
1884 }
1885 else
1886 ShClTransferListHdrDestroy(pListHdr);
1887 }
1888
1889 LogFlowFuncLeaveRC(rc);
1890 return rc;
1891}
1892
1893/** @copydoc SHCLTXPROVIDERIFACE::pfnListEntryRead */
1894static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceListEntryRead(PSHCLTXPROVIDERCTX pCtx,
1895 SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry)
1896{
1897 LogFlowFuncEnter();
1898
1899 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1900 AssertPtr(pCmdCtx);
1901
1902 int rc = VbglR3ClipboardTransferListEntryRead(pCmdCtx, hList, pListEntry);
1903
1904 LogFlowFuncLeaveRC(rc);
1905 return rc;
1906}
1907
1908/** @copydoc SHCLTXPROVIDERIFACE::pfnObjOpen */
1909static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjOpen(PSHCLTXPROVIDERCTX pCtx,
1910 PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)
1911{
1912 LogFlowFuncEnter();
1913
1914 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1915 AssertPtr(pCmdCtx);
1916
1917 int rc = VbglR3ClipboardTransferObjOpenSend(pCmdCtx, pCreateParms, phObj);
1918
1919 LogFlowFuncLeaveRC(rc);
1920 return rc;
1921}
1922
1923/** @copydoc SHCLTXPROVIDERIFACE::pfnObjClose */
1924static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjClose(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)
1925{
1926 LogFlowFuncEnter();
1927
1928 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1929 AssertPtr(pCmdCtx);
1930
1931 int rc = VbglR3ClipboardTransferObjCloseSend(pCmdCtx, hObj);
1932
1933 LogFlowFuncLeaveRC(rc);
1934 return rc;
1935}
1936
1937/** @copydoc SHCLTXPROVIDERIFACE::pfnObjRead */
1938static DECLCALLBACK(int) vbglR3ClipboardTransferIfaceObjRead(PSHCLTXPROVIDERCTX pCtx,
1939 SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData,
1940 uint32_t fFlags, uint32_t *pcbRead)
1941{
1942 LogFlowFuncEnter();
1943
1944 PVBGLR3SHCLCMDCTX pCmdCtx = (PVBGLR3SHCLCMDCTX)pCtx->pvUser;
1945 AssertPtr(pCmdCtx);
1946
1947 RT_NOREF(fFlags); /* Not used yet. */
1948
1949 int rc = VbglR3ClipboardTransferObjReadSend(pCmdCtx, hObj, pvData, cbData, pcbRead);
1950
1951 LogFlowFuncLeaveRC(rc);
1952 return rc;
1953}
1954
1955/**
1956 * Creates (and registers) a transfer on the guest side.
1957 *
1958 * @returns VBox status code.
1959 * @param pCmdCtx Command context to use.
1960 * @param pTransferCtx Transfer context to init transfer for.
1961 * @param enmDir Specifies the transfer direction of this transfer.
1962 * @param enmSource Specifies the data source of the transfer.
1963 * @param idTransfer ID of transfer to create.
1964 * @param ppTransfer Where to return the transfer object on success. Optional.
1965 */
1966static int vbglR3ClipboardTransferCreate(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
1967 SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource, SHCLTRANSFERID idTransfer,
1968 PSHCLTRANSFER *ppTransfer)
1969{
1970 AssertReturn(idTransfer != NIL_SHCLTRANSFERID, VERR_WRONG_ORDER);
1971
1972 RT_NOREF(pCmdCtx);
1973
1974 PSHCLTRANSFER pTransfer;
1975 int rc = ShClTransferCreate(enmDir, enmSource, &pTransfer);
1976 if (RT_SUCCESS(rc))
1977 {
1978 /* Set the callbacks the (OS-dependent) implementation relies on. Optional. */
1979 ShClTransferSetCallbacks(pTransfer, &pCmdCtx->Transfers.Callbacks);
1980
1981 rc = ShClTransferCtxRegisterById(pTransferCtx, pTransfer, idTransfer);
1982 if ( RT_SUCCESS(rc)
1983 && ppTransfer)
1984 *ppTransfer = pTransfer;
1985 }
1986
1987 if (RT_SUCCESS(rc))
1988 LogRel(("Shared Clipboard: Transfer %RU32 successfully created\n", idTransfer));
1989 else
1990 LogRel(("Shared Clipboard: Error creating transfer %RU32, rc=%Rrc\n", idTransfer, rc));
1991
1992 LogFlowFuncLeaveRC(rc);
1993 return rc;
1994}
1995
1996/**
1997 * Initializes a transfer on the guest side.
1998 *
1999 * @returns VBox status code.
2000 * @param pCmdCtx Command context to use.
2001 * @param pTransfer Transfer to init.
2002 */
2003static int vbglR3ClipboardTransferInit(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFER pTransfer)
2004{
2005 LogFlowFuncEnter();
2006
2007 SHCLTRANSFERDIR const enmDir = ShClTransferGetDir(pTransfer);
2008
2009 SHCLTXPROVIDER Provider;
2010 RT_ZERO(Provider);
2011
2012 /* Assign local provider first and overwrite interface methods below if needed. */
2013 ShClTransferProviderLocalQueryInterface(&Provider);
2014
2015 /* If this is a read transfer (reading data from host), set the interface to use
2016 * our VbglR3 routines here. */
2017 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* Host -> Guest */
2018 {
2019 Provider.Interface.pfnRootListRead = vbglR3ClipboardTransferIfaceRootListRead;
2020
2021 Provider.Interface.pfnListOpen = vbglR3ClipboardTransferIfaceListOpen;
2022 Provider.Interface.pfnListClose = vbglR3ClipboardTransferIfaceListClose;
2023 Provider.Interface.pfnListHdrRead = vbglR3ClipboardTransferIfaceListHdrRead;
2024 Provider.Interface.pfnListEntryRead = vbglR3ClipboardTransferIfaceListEntryRead;
2025
2026 Provider.Interface.pfnObjOpen = vbglR3ClipboardTransferIfaceObjOpen;
2027 Provider.Interface.pfnObjClose = vbglR3ClipboardTransferIfaceObjClose;
2028 Provider.Interface.pfnObjRead = vbglR3ClipboardTransferIfaceObjRead;
2029 }
2030 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* Guest -> Host */
2031 {
2032 /* Uses the local provider assigned above. */
2033 }
2034 else
2035 AssertFailed();
2036
2037 Provider.pvUser = pCmdCtx;
2038
2039 /* Set the provider first before calling ShClTransferInit(), as the init callback might utilize some of the
2040 * provider functions. */
2041 int rc = ShClTransferSetProvider(pTransfer, &Provider);
2042 if (RT_SUCCESS(rc))
2043 {
2044 rc = ShClTransferInit(pTransfer);
2045 if (RT_SUCCESS(rc))
2046 {
2047 /* As soon as we report the INITIALIZED state to the host, the host can start reading stuff from the transfer.
2048 * So make sure that we really are ready here. */
2049 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE)
2050 AssertMsgStmt(ShClTransferRootsCount(pTransfer), ("No root entries set yet!\n"
2051 "Those have to be present as soon we report the transfer as being INITIALIZED to the host\n"),
2052 rc = VERR_WRONG_ORDER);
2053 }
2054 }
2055
2056 SHCLTRANSFERID const idTransfer = ShClTransferGetID(pTransfer);
2057
2058 if (RT_SUCCESS(rc))
2059 {
2060 LogRel(("Shared Clipboard: Transfer %RU32 (%s) successfully initialized\n",
2061 idTransfer, enmDir == SHCLTRANSFERDIR_FROM_REMOTE ? "host -> guest" : "guest -> host"));
2062 }
2063 else
2064 LogRel(("Shared Clipboard: Unable to initialize transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2065
2066 LogFlowFuncLeaveRC(rc);
2067 return rc;
2068}
2069
2070/**
2071 * Destroys a transfer on the guest side.
2072 *
2073 * @returns VBox status code.
2074 * @param pCmdCtx Command context to use.
2075 * @param pTransferCtx Transfer context to uninit transfer for.
2076 * @param idTransfer ID of transfer to initialize.
2077 */
2078static int vbglR3ClipboardTransferDestroy(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer)
2079{
2080 RT_NOREF(pCmdCtx);
2081
2082 LogFlowFuncEnter();
2083
2084 int rc;
2085
2086 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2087 if (pTransfer)
2088 {
2089 rc = ShClTransferCtxUnregisterById(pTransferCtx, idTransfer);
2090 if (RT_SUCCESS(rc))
2091 rc = ShClTransferDestroy(pTransfer);
2092
2093 if (RT_SUCCESS(rc))
2094 {
2095 LogRel(("Shared Clipboard: Transfer %RU32 successfully uninitialized\n", idTransfer));
2096 }
2097 else
2098 LogRel(("Shared Clipboard: Unable to uninitialized transfer %RU32, rc=%Rrc\n", idTransfer, rc));
2099 }
2100 else
2101 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2102
2103 /* Send a reply in any case. */
2104 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2105 RT_SUCCESS(rc)
2106 ? SHCLTRANSFERSTATUS_UNINITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2107
2108 /* The host might not have the transfer around anymore at this time, so simply ignore this error. */
2109 if (rc2 == VERR_SHCLPB_TRANSFER_ID_NOT_FOUND)
2110 rc2 = VINF_SUCCESS;
2111
2112 if (RT_SUCCESS(rc))
2113 rc = rc2;
2114
2115 LogFlowFuncLeaveRC(rc);
2116 return rc;
2117}
2118
2119/**
2120 * Requests a new transfer from the host.
2121 *
2122 * On success this will issue an INITIALIZED status reply from the host with a transfer ID set.
2123 * This ID will be used to initialize the transfer on the guest side then.
2124 *
2125 * @returns VBox status code.
2126 * @param pCmdCtx Command context to use.
2127 */
2128VBGLR3DECL(int) VbglR3ClipboardTransferRequest(PVBGLR3SHCLCMDCTX pCmdCtx)
2129{
2130 LogFlowFuncEnter();
2131
2132 LogRel2(("Shared Clipboard: Requesting new host -> guest transfer from host\n"));
2133
2134 int rc = vbglR3ClipboardTransferStatusReplyEx(pCmdCtx, 0 /* Context ID not needed */,
2135 SHCLTRANSFERSTATUS_REQUESTED, VINF_SUCCESS);
2136 LogFlowFuncLeaveRC(rc);
2137 return rc;
2138}
2139
2140/**
2141 * Starts a transfer on the guest side.
2142 *
2143 * @returns VBox status code.
2144 * @param pCmdCtx Command context to use.
2145 * @param pTransferCtx Transfer context to start transfer for.
2146 * @param uTransferID ID to use for transfer to start.
2147 */
2148static int vbglR3ClipboardTransferStart(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2149 SHCLTRANSFERID uTransferID)
2150{
2151 RT_NOREF(pCmdCtx);
2152
2153 LogFlowFuncEnter();
2154
2155 int rc;
2156
2157 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2158 if (pTransfer)
2159 {
2160 rc = ShClTransferStart(pTransfer);
2161 if (RT_SUCCESS(rc))
2162 {
2163 LogRel(("Shared Clipboard: Transfer %RU32 successfully started\n", uTransferID));
2164 }
2165 else
2166 LogRel(("Shared Clipboard: Unable to start transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2167 }
2168 else
2169 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2170
2171 /* Send a reply in any case. */
2172 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2173 RT_SUCCESS(rc)
2174 ? SHCLTRANSFERSTATUS_STARTED : SHCLTRANSFERSTATUS_ERROR, rc);
2175 if (RT_SUCCESS(rc))
2176 rc = rc2;
2177
2178 LogFlowFuncLeaveRC(rc);
2179 return rc;
2180}
2181
2182/**
2183 * Stops a transfer on the guest side.
2184 *
2185 * @returns VBox status code, or VERR_NOT_FOUND if transfer has not been found.
2186 * @param pCmdCtx Command context to use.
2187 * @param pTransferCtx Transfer context to stop transfer for.
2188 * @param uTransferID ID of transfer to stop.
2189 */
2190static int vbglR3ClipboardTransferStop(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2191 SHCLTRANSFERID uTransferID)
2192{
2193 LogFlowFuncEnter();
2194
2195 int rc;
2196
2197 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, uTransferID);
2198 if (pTransfer)
2199 {
2200 rc = ShClTransferCtxUnregisterById(pTransferCtx, uTransferID);
2201 if (RT_SUCCESS(rc))
2202 {
2203 LogRel(("Shared Clipboard: Transfer %RU32 successfully stopped\n", uTransferID));
2204 }
2205 else
2206 LogRel(("Shared Clipboard: Unable to stop transfer %RU32, rc=%Rrc\n", uTransferID, rc));
2207 }
2208 else
2209 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2210
2211 /* Send a reply in any case. */
2212 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2213 RT_SUCCESS(rc)
2214 ? SHCLTRANSFERSTATUS_STOPPED : SHCLTRANSFERSTATUS_ERROR, rc);
2215 if (RT_SUCCESS(rc))
2216 rc = rc2;
2217
2218 LogFlowFuncLeaveRC(rc);
2219 return rc;
2220}
2221
2222/**
2223 * Sets transfer callbacks of a Shared Clipboard command context.
2224 *
2225 * @param pCmdCtx Command context to set callbacks for.
2226 * @param pCallbacks Pointer to callback table to set.
2227 */
2228VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCALLBACKS pCallbacks)
2229{
2230 AssertPtrReturnVoid(pCmdCtx);
2231 AssertPtrReturnVoid(pCallbacks);
2232
2233 ShClTransferCopyCallbacks(&pCmdCtx->Transfers.Callbacks, pCallbacks);
2234}
2235
2236VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms,
2237 PVBGLR3SHCLCMDCTX pCmdCtx, PSHCLTRANSFERCTX pTransferCtx,
2238 PVBGLR3CLIPBOARDEVENT pEvent)
2239{
2240 AssertPtrReturn(pCmdCtx, VERR_INVALID_POINTER);
2241 AssertPtrReturn(pTransferCtx, VERR_INVALID_POINTER);
2242 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2243
2244 LogFunc(("Handling idMsg=%RU32 (%s), cParms=%RU32\n", idMsg, ShClHostMsgToStr(idMsg), cParms));
2245
2246 int rc;
2247 if (!pCmdCtx->fUseLegacyProtocol)
2248 {
2249 bool fErrorSent = false; /* Whether an error has been reported back to the host already. */
2250
2251 switch (idMsg)
2252 {
2253 case VBOX_SHCL_HOST_MSG_TRANSFER_STATUS:
2254 {
2255 SHCLTRANSFERDIR enmDir;
2256 SHCLTRANSFERREPORT transferReport;
2257 rc = VbglR3ClipboarTransferStatusRecv(pCmdCtx, &enmDir, &transferReport);
2258 if (RT_SUCCESS(rc))
2259 {
2260 const SHCLTRANSFERID idTransfer = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2261
2262 LogRel(("Shared Clipboard: Received status %s (%Rrc) for transfer %RU32\n",
2263 ShClTransferStatusToStr(transferReport.uStatus), transferReport.rc, idTransfer));
2264
2265 SHCLSOURCE enmSource = SHCLSOURCE_INVALID;
2266
2267 switch (transferReport.uStatus)
2268 {
2269 case SHCLTRANSFERSTATUS_REQUESTED: /* Only used for H->G transfers. */
2270 {
2271 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2272 enmSource = SHCLSOURCE_REMOTE;
2273
2274 /* The host acknowledged our request to create a new transfer.
2275 * So create a new transfer here with the transfer ID we just got from the host.
2276 *
2277 * Actual initialization will be done as soon as the host sends use the INITIALIZED status for it.
2278 */
2279 PSHCLTRANSFER pTransfer;
2280 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2281
2282 /* As soon as we've created our transfer locally, report back INITIALIZED to the host.
2283 * This will initialize the transfer on the host, so that in turn reports INITIALIZED
2284 * back to us (see case down below).*/
2285 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2286 RT_SUCCESS(rc)
2287 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2288 if (RT_SUCCESS(rc))
2289 rc = rc2;
2290 break;
2291 }
2292
2293 case SHCLTRANSFERSTATUS_INITIALIZED:
2294 {
2295 /* The host announces the transfer direction from its point of view, so inverse the direction here. */
2296 if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* H -> G */
2297 {
2298 enmDir = SHCLTRANSFERDIR_FROM_REMOTE;
2299 enmSource = SHCLSOURCE_REMOTE;
2300 }
2301 else if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* G -> H */
2302 {
2303 enmDir = SHCLTRANSFERDIR_TO_REMOTE;
2304 enmSource = SHCLSOURCE_LOCAL;
2305 }
2306 else
2307 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2308
2309 if (enmDir == SHCLTRANSFERDIR_FROM_REMOTE) /* H->G */
2310 {
2311 /* The host reported INITIALIZED for the transfer.
2312 * So init our local transfer as well now. */
2313 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx, idTransfer);
2314 if (pTransfer)
2315 {
2316 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2317
2318 /* Only send back a reply on error -- we already reported INITIALIZED
2319 * in the case SHCLTRANSFERSTATUS_REQUESTED above. */
2320 if (RT_FAILURE(rc))
2321 {
2322 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2323 SHCLTRANSFERSTATUS_ERROR, rc);
2324 AssertRC(rc2);
2325 }
2326 }
2327 else
2328 rc = VERR_SHCLPB_TRANSFER_ID_NOT_FOUND;
2329 }
2330 else if (enmDir == SHCLTRANSFERDIR_TO_REMOTE) /* G->H */
2331 {
2332 /* The host reported the INITIALIZED status together with the transfer ID.
2333 * So create a local transfer here with that ID. */
2334 PSHCLTRANSFER pTransfer;
2335 rc = vbglR3ClipboardTransferCreate(pCmdCtx, pTransferCtx, enmDir, enmSource, idTransfer, &pTransfer);
2336 if (RT_SUCCESS(rc))
2337 rc = vbglR3ClipboardTransferInit(pCmdCtx, pTransfer);
2338
2339 /* Send a reply in any case. */
2340 int rc2 = VbglR3ClipboardTransferStatusReply(pCmdCtx, pTransfer,
2341 RT_SUCCESS(rc)
2342 ? SHCLTRANSFERSTATUS_INITIALIZED : SHCLTRANSFERSTATUS_ERROR, rc);
2343 if (RT_SUCCESS(rc))
2344 rc = rc2;
2345 }
2346 else
2347 AssertFailedBreakStmt(rc = VERR_INVALID_PARAMETER);
2348
2349 break;
2350 }
2351
2352 case SHCLTRANSFERSTATUS_UNINITIALIZED:
2353 {
2354 rc = vbglR3ClipboardTransferDestroy(pCmdCtx, pTransferCtx, idTransfer);
2355 break;
2356 }
2357
2358 case SHCLTRANSFERSTATUS_STARTED:
2359 {
2360 rc = vbglR3ClipboardTransferStart(pCmdCtx, pTransferCtx, idTransfer);
2361 break;
2362 }
2363
2364 case SHCLTRANSFERSTATUS_STOPPED:
2365 RT_FALL_THROUGH();
2366 case SHCLTRANSFERSTATUS_CANCELED:
2367 RT_FALL_THROUGH();
2368 case SHCLTRANSFERSTATUS_KILLED:
2369 RT_FALL_THROUGH();
2370 case SHCLTRANSFERSTATUS_ERROR:
2371 {
2372 rc = vbglR3ClipboardTransferStop(pCmdCtx, pTransferCtx, idTransfer);
2373 break;
2374 }
2375
2376 default:
2377 LogRel(("Shared Clipboard: Received unknown status %#x (%Rrc) for transfer %RU32\n",
2378 pEvent->u.TransferStatus.Report.rc,
2379 pEvent->u.TransferStatus.uID));
2380 rc = VERR_NOT_SUPPORTED;
2381 break;
2382 }
2383
2384 if (RT_SUCCESS(rc))
2385 {
2386 pEvent->u.TransferStatus.enmDir = enmDir;
2387 pEvent->u.TransferStatus.Report = transferReport;
2388 pEvent->u.TransferStatus.uID = VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext);
2389
2390 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS;
2391 }
2392 }
2393 break;
2394 }
2395
2396 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ:
2397 {
2398 uint32_t fRoots;
2399 rc = VbglR3ClipboardTransferRootListHdrReadReq(pCmdCtx, &fRoots);
2400
2401 /** @todo Validate / handle fRoots. */
2402
2403 if (RT_SUCCESS(rc))
2404 {
2405 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2406 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2407 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2408
2409 SHCLLISTHDR rootListHdr;
2410 ShClTransferListHdrInit(&rootListHdr);
2411
2412 rootListHdr.cEntries = ShClTransferRootsCount(pTransfer);
2413
2414 LogFlowFunc(("cRoots=%RU32\n", rootListHdr.cEntries));
2415
2416 rc = VbglR3ClipboardTransferRootListHdrReadReply(pCmdCtx, &rootListHdr);
2417 }
2418 break;
2419 }
2420
2421 case VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ:
2422 {
2423 uint64_t uIndex;
2424 uint32_t fInfo;
2425 rc = VbglR3ClipboardTransferRootListEntryReadReq(pCmdCtx, &uIndex, &fInfo);
2426 if (RT_SUCCESS(rc))
2427 {
2428 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2429 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2430 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2431
2432 PCSHCLLISTENTRY pEntry = ShClTransferRootsEntryGet(pTransfer, uIndex);
2433 if (pEntry)
2434 {
2435 rc = VbglR3ClipboardTransferRootListEntryReadReply(pCmdCtx, uIndex, pEntry);
2436 }
2437 else
2438 rc = VERR_NOT_FOUND;
2439 }
2440 break;
2441 }
2442
2443 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN:
2444 {
2445 SHCLLISTOPENPARMS openParmsList;
2446 rc = ShClTransferListOpenParmsInit(&openParmsList);
2447 if (RT_SUCCESS(rc))
2448 {
2449 rc = VbglR3ClipboardTransferListOpenRecv(pCmdCtx, &openParmsList);
2450 if (RT_SUCCESS(rc))
2451 {
2452 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2453 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2454 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2455
2456 LogFlowFunc(("pszPath=%s\n", openParmsList.pszPath));
2457
2458 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2459 rc = ShClTransferListOpen(pTransfer, &openParmsList, &hList);
2460
2461 /* Reply in any case. */
2462 int rc2 = VbglR3ClipboardTransferListOpenReply(pCmdCtx, rc, hList);
2463 AssertRC(rc2);
2464 }
2465
2466 ShClTransferListOpenParmsDestroy(&openParmsList);
2467 }
2468
2469 break;
2470 }
2471
2472 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE:
2473 {
2474 SHCLLISTHANDLE hList;
2475 rc = VbglR3ClipboardTransferListCloseRecv(pCmdCtx, &hList);
2476 if (RT_SUCCESS(rc))
2477 {
2478 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2479 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2480 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2481
2482 rc = ShClTransferListClose(pTransfer, hList);
2483
2484 /* Reply in any case. */
2485 int rc2 = VbglR3ClipboardTransferListCloseReply(pCmdCtx, rc, hList);
2486 AssertRC(rc2);
2487 }
2488
2489 break;
2490 }
2491
2492 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ:
2493 {
2494 /** @todo Handle filter + list features. */
2495
2496 SHCLLISTHANDLE hList = NIL_SHCLLISTHANDLE;
2497 uint32_t fFlags = 0;
2498 rc = VbglR3ClipboardTransferListHdrReadRecvReq(pCmdCtx, &hList, &fFlags);
2499 if (RT_SUCCESS(rc))
2500 {
2501 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2502 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2503 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2504
2505 SHCLLISTHDR hdrList;
2506 rc = ShClTransferListGetHeader(pTransfer, hList, &hdrList);
2507 if (RT_SUCCESS(rc))
2508 {
2509 rc = VbglR3ClipboardTransferListHdrWrite(pCmdCtx, hList, &hdrList);
2510
2511 ShClTransferListHdrDestroy(&hdrList);
2512 }
2513 }
2514
2515 break;
2516 }
2517
2518 case VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ:
2519 {
2520 LogFlowFunc(("VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ\n"));
2521
2522 SHCLLISTENTRY entryList;
2523 rc = ShClTransferListEntryInit(&entryList);
2524 if (RT_SUCCESS(rc))
2525 {
2526 SHCLLISTHANDLE hList;
2527 uint32_t fInfo;
2528 rc = VbglR3ClipboardTransferListEntryReadRecvReq(pCmdCtx, &hList, &fInfo);
2529 if (RT_SUCCESS(rc))
2530 {
2531 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2532 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2533 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2534
2535 rc = ShClTransferListRead(pTransfer, hList, &entryList);
2536 if (RT_SUCCESS(rc))
2537 {
2538 PSHCLFSOBJINFO pObjInfo = (PSHCLFSOBJINFO)entryList.pvInfo;
2539 Assert(entryList.cbInfo == sizeof(SHCLFSOBJINFO));
2540
2541 RT_NOREF(pObjInfo);
2542
2543 LogFlowFunc(("\t%s (%RU64 bytes)\n", entryList.pszName, pObjInfo->cbObject));
2544
2545 rc = VbglR3ClipboardTransferListEntryWrite(pCmdCtx, hList, &entryList);
2546 }
2547 }
2548
2549 ShClTransferListEntryDestroy(&entryList);
2550 }
2551
2552 break;
2553 }
2554
2555 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN:
2556 {
2557 SHCLOBJOPENCREATEPARMS openParms;
2558 rc = ShClTransferObjOpenParmsInit(&openParms);
2559 if (RT_SUCCESS(rc))
2560 {
2561 rc = VbglR3ClipboardTransferObjOpenRecv(pCmdCtx, &openParms);
2562 if (RT_SUCCESS(rc))
2563 {
2564 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2565 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2566 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2567
2568 SHCLOBJHANDLE hObj;
2569 rc = ShClTransferObjOpen(pTransfer, &openParms, &hObj);
2570
2571 /* Reply in any case. */
2572 int rc2 = VbglR3ClipboardTransferObjOpenReply(pCmdCtx, rc, hObj);
2573 AssertRC(rc2);
2574 }
2575
2576 ShClTransferObjOpenParmsDestroy(&openParms);
2577 }
2578
2579 break;
2580 }
2581
2582 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE:
2583 {
2584 SHCLOBJHANDLE hObj;
2585 rc = VbglR3ClipboardTransferObjCloseRecv(pCmdCtx, &hObj);
2586 if (RT_SUCCESS(rc))
2587 {
2588 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2589 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2590 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2591
2592 rc = ShClTransferObjClose(pTransfer, hObj);
2593
2594 /* Reply in any case. */
2595 int rc2 = VbglR3ClipboardTransferObjCloseReply(pCmdCtx, rc, hObj);
2596 AssertRC(rc2);
2597 }
2598
2599 break;
2600 }
2601
2602 case VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ:
2603 {
2604 SHCLOBJHANDLE hObj;
2605 uint32_t cbBuf;
2606 uint32_t fFlags;
2607 rc = VbglR3ClipboardTransferObjReadRecv(pCmdCtx, &hObj, &cbBuf, &fFlags);
2608 if (RT_SUCCESS(rc))
2609 {
2610 PSHCLTRANSFER pTransfer = ShClTransferCtxGetTransferById(pTransferCtx,
2611 VBOX_SHCL_CONTEXTID_GET_TRANSFER(pCmdCtx->idContext));
2612 AssertPtrBreakStmt(pTransfer, rc = VERR_NOT_FOUND);
2613
2614 AssertBreakStmt(pCmdCtx->Transfers.cbChunkSize, rc = VERR_INVALID_PARAMETER);
2615
2616 const uint32_t cbToRead = RT_MIN(cbBuf, pCmdCtx->Transfers.cbChunkSize);
2617
2618 LogFlowFunc(("hObj=%RU64, cbBuf=%RU32, fFlags=0x%x -> cbChunkSize=%RU32, cbToRead=%RU32\n",
2619 hObj, cbBuf, fFlags, pCmdCtx->Transfers.cbChunkSize, cbToRead));
2620
2621 void *pvBuf = RTMemAlloc(cbToRead);
2622 if (pvBuf)
2623 {
2624 uint32_t cbRead;
2625 rc = ShClTransferObjRead(pTransfer, hObj, pvBuf, cbToRead, fFlags, &cbRead);
2626 if (RT_SUCCESS(rc))
2627 rc = VbglR3ClipboardTransferObjWriteSend(pCmdCtx, hObj, pvBuf, cbRead, NULL /* pcbWritten */);
2628
2629 RTMemFree(pvBuf);
2630 }
2631 else
2632 rc = VERR_NO_MEMORY;
2633 }
2634
2635 break;
2636 }
2637
2638 default:
2639 {
2640 rc = VbglR3ClipboardEventGetNext(idMsg, cParms, pCmdCtx, pEvent);
2641 if (RT_FAILURE(rc))
2642 fErrorSent = true;
2643 break;
2644 }
2645 }
2646
2647 if ( !fErrorSent
2648 && RT_FAILURE(rc))
2649 {
2650 /* Report error back to the host. */
2651 int rc2 = VbglR3ClipboardWriteError(pCmdCtx->idClient, rc);
2652 AssertRC(rc2);
2653 }
2654 }
2655 else
2656 {
2657 /*
2658 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2659 * !HACK ALERT! cParms is the format flag or flags.
2660 */
2661 rc = VINF_SUCCESS;
2662 switch (idMsg)
2663 {
2664 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2665 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2666 pEvent->u.fReportedFormats = cParms;
2667 break;
2668
2669 case VBOX_SHCL_HOST_MSG_READ_DATA:
2670 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2671 pEvent->u.fReadData = cParms;
2672 break;
2673
2674 case VBOX_SHCL_HOST_MSG_QUIT:
2675 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2676 break;
2677
2678 default:
2679 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2680 rc = VERR_NOT_SUPPORTED;
2681 break;
2682 }
2683 }
2684
2685 LogFlowFuncLeaveRC(rc);
2686 return rc;
2687}
2688
2689#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */
2690
2691VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent)
2692{
2693 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2694 AssertPtrReturn(pEvent, VERR_INVALID_POINTER);
2695
2696 RT_NOREF(cParms);
2697
2698 int rc;
2699 if (!pCtx->fUseLegacyProtocol)
2700 {
2701 LogFunc(("Handling idMsg=%RU32 (%s)\n", idMsg, ShClHostMsgToStr(idMsg)));
2702 switch (idMsg)
2703 {
2704 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2705 {
2706 rc = vbglR3ClipboardFormatsReportRecv(pCtx, &pEvent->u.fReportedFormats);
2707 if (RT_SUCCESS(rc))
2708 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2709 break;
2710 }
2711
2712 case VBOX_SHCL_HOST_MSG_READ_DATA_CID:
2713 {
2714 rc = vbglR3ClipboardFetchReadDataCid(pCtx, &pEvent->u.fReadData);
2715 if (RT_SUCCESS(rc))
2716 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2717 break;
2718 }
2719
2720 case VBOX_SHCL_HOST_MSG_READ_DATA:
2721 {
2722 rc = vbglR3ClipboardFetchReadData(pCtx, &pEvent->u.fReadData);
2723 if (RT_SUCCESS(rc))
2724 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2725 break;
2726 }
2727
2728 case VBOX_SHCL_HOST_MSG_QUIT:
2729 {
2730 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2731 rc = VINF_SUCCESS;
2732 break;
2733 }
2734
2735 default:
2736 {
2737 /** @todo r=bird: BUGBUG - need a skip command here! */
2738 rc = VERR_NOT_SUPPORTED;
2739 break;
2740 }
2741 }
2742
2743 if (RT_SUCCESS(rc))
2744 {
2745 /* Copy over our command context to the event. */
2746 pEvent->cmdCtx = *pCtx;
2747 }
2748 else
2749 {
2750 /* Report error back to the host. */
2751 int rc2 = VbglR3ClipboardWriteError(pCtx->idClient, rc);
2752 AssertRC(rc2);
2753 }
2754 }
2755 else
2756 {
2757 /*
2758 * This builds on what we did in VbglR3ClipboardMsgPeekWait, so
2759 * !HACK ALERT! cParms is the format flag or flags.
2760 */
2761 rc = VINF_SUCCESS;
2762 switch (idMsg)
2763 {
2764 case VBOX_SHCL_HOST_MSG_FORMATS_REPORT:
2765 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS;
2766 pEvent->u.fReportedFormats = cParms;
2767 break;
2768
2769 case VBOX_SHCL_HOST_MSG_READ_DATA:
2770 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_READ_DATA;
2771 pEvent->u.fReadData = cParms;
2772 break;
2773
2774 case VBOX_SHCL_HOST_MSG_QUIT:
2775 pEvent->enmType = VBGLR3CLIPBOARDEVENTTYPE_QUIT;
2776 break;
2777
2778 default:
2779 AssertMsgFailed(("%u (%#x)\n", idMsg, idMsg));
2780 rc = VERR_NOT_SUPPORTED;
2781 break;
2782 }
2783 pEvent->cmdCtx = *pCtx;
2784 }
2785
2786 LogFlowFuncLeaveRC(rc);
2787 return rc;
2788}
2789
2790/**
2791 * Frees (destroys) a formerly allocated Shared Clipboard event.
2792 *
2793 * @returns IPRT status code.
2794 * @param pEvent Event to free (destroy).
2795 */
2796VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent)
2797{
2798 if (!pEvent)
2799 return;
2800
2801 /* Some messages require additional cleanup. */
2802 switch (pEvent->enmType)
2803 {
2804 default:
2805 break;
2806 }
2807
2808 RTMemFree(pEvent);
2809 pEvent = NULL;
2810}
2811
2812/**
2813 * Reports (advertises) guest clipboard formats to the host.
2814 *
2815 * Legacy function, do not use anymore.
2816 *
2817 * @returns VBox status code.
2818 * @param idClient The client id returned by VbglR3ClipboardConnect().
2819 * @param fFormats The formats to report.
2820 */
2821VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats)
2822{
2823 struct
2824 {
2825 VBGLIOCHGCMCALL Hdr;
2826 VBoxShClParmReportFormats Parms;
2827 } Msg;
2828
2829 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_REPORT_FORMATS, VBOX_SHCL_CPARMS_REPORT_FORMATS);
2830 VbglHGCMParmUInt32Set(&Msg.Parms.f32Formats, fFormats);
2831
2832 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2833
2834 LogFlowFuncLeaveRC(rc);
2835 return rc;
2836}
2837
2838/**
2839 * Sends guest clipboard data to the host.
2840 *
2841 * Legacy function kept for compatibility, do not use anymore.
2842 *
2843 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2844 * from the host.
2845 *
2846 * @returns VBox status code.
2847 * @param idClient The client id returned by VbglR3ClipboardConnect().
2848 * @param fFormat The format of the data.
2849 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2850 * is zero.
2851 * @param cbData Number of bytes of data to send. Zero is valid.
2852 */
2853VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb)
2854{
2855 LogFlowFuncEnter();
2856
2857 struct
2858 {
2859 VBGLIOCHGCMCALL Hdr;
2860 VBoxShClParmDataWriteOld Parms;
2861 } Msg;
2862
2863 VBGL_HGCM_HDR_INIT(&Msg.Hdr, idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE_OLD);
2864 VbglHGCMParmUInt32Set(&Msg.Parms.f32Format, fFormat);
2865 VbglHGCMParmPtrSet(&Msg.Parms.pData, pv, cb);
2866
2867 int rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2868
2869 LogFlowFuncLeaveRC(rc);
2870 return rc;
2871}
2872
2873/**
2874 * Sends guest clipboard data to the host.
2875 *
2876 * This is usually called in reply to a VBOX_SHCL_HOST_MSG_READ_DATA message
2877 * from the host.
2878 *
2879 * @returns VBox status code.
2880 * @param pCtx The command context returned by VbglR3ClipboardConnectEx().
2881 * @param fFormat Clipboard format to send.
2882 * @param pvData Pointer to the data to send. Can be NULL if @a cbData
2883 * is zero.
2884 * @param cbData Number of bytes of data to send. Zero is valid.
2885 */
2886VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData)
2887{
2888 AssertPtrReturn(pCtx, VERR_INVALID_POINTER);
2889 AssertReturn(cbData == 0 || RT_VALID_PTR(pvData), VERR_INVALID_PARAMETER);
2890
2891 LogFlowFunc(("fFormat=%#x pvData=%p cbData=%#x\n", fFormat, pvData, cbData));
2892
2893 int rc;
2894 if (pCtx->fUseLegacyProtocol)
2895 rc = VbglR3ClipboardWriteData(pCtx->idClient, fFormat, pvData, cbData);
2896 else
2897 {
2898 struct
2899 {
2900 VBGLIOCHGCMCALL Hdr;
2901 VBoxShClParmDataWrite Parms;
2902 } Msg;
2903
2904 VBGL_HGCM_HDR_INIT(&Msg.Hdr, pCtx->idClient, VBOX_SHCL_GUEST_FN_DATA_WRITE, VBOX_SHCL_CPARMS_DATA_WRITE);
2905 Msg.Parms.id64Context.SetUInt64(pCtx->idContext);
2906 Msg.Parms.f32Format.SetUInt32(fFormat);
2907 Msg.Parms.pData.SetPtr(pvData, cbData);
2908
2909 LogFlowFunc(("CID=%RU32\n", pCtx->idContext));
2910
2911 rc = VbglR3HGCMCall(&Msg.Hdr, sizeof(Msg));
2912 }
2913
2914 LogFlowFuncLeaveRC(rc);
2915 return rc;
2916}
2917
2918/**
2919 * Writes an error to the host.
2920 *
2921 * @returns IPRT status code.
2922 * @param idClient The client id returned by VbglR3ClipboardConnect().
2923 * @param rcErr Error (IPRT-style) to send.
2924 */
2925VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr)
2926{
2927 AssertReturn(idClient, VERR_INVALID_PARAMETER);
2928
2929 VBoxShClWriteErrorMsg Msg;
2930 VBGL_HGCM_HDR_INIT(&Msg.hdr, idClient, VBOX_SHCL_GUEST_FN_ERROR, VBOX_SHCL_CPARMS_ERROR);
2931
2932 /** @todo Context ID not used yet. */
2933 Msg.uContext.SetUInt64(0);
2934 Msg.rc.SetUInt32((uint32_t)rcErr); /* uint32_t vs. int. */
2935
2936 int rc = VbglR3HGCMCall(&Msg.hdr, sizeof(Msg));
2937
2938 if (RT_FAILURE(rc))
2939 LogFlowFunc(("Sending error %Rrc failed with rc=%Rrc\n", rcErr, rc));
2940 if (rc == VERR_NOT_SUPPORTED)
2941 rc = VINF_SUCCESS;
2942
2943 if (RT_FAILURE(rc))
2944 LogRel(("Shared Clipboard: Reporting error %Rrc to the host failed with %Rrc\n", rcErr, rc));
2945
2946 LogFlowFuncLeaveRC(rc);
2947 return rc;
2948}
2949
Note: See TracBrowser for help on using the repository browser.

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