VirtualBox

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

最後變更 在這個檔案從103165是 101720,由 vboxsync 提交於 17 月 前

Additions: Guest Library: Fix valgrind warnings about uninitialized memory usage, bugref:10194.

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

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