VirtualBox

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

最後變更 在這個檔案從103442是 103442,由 vboxsync 提交於 13 月 前

Shared Clipboard: Condensed more code by adding a SHCLTRANSFERCALLBACKS::pfnOnInitialize() callback function. bugref:9437

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

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